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

How-To Tutorials

7019 Articles
article-image-overview-tomcat-6-servlet-container-part-2
Packt
18 Jan 2010
8 min read
Save for later

An Overview of Tomcat 6 Servlet Container: Part 2

Packt
18 Jan 2010
8 min read
Nested components These components are specific to the Tomcat implementation, and their primary purpose is to enable the various Tomcat containers to perform their tasks. Valve A valve is a processing element that can be placed within the processing path of each of Tomcat's containers—engine, host, context, or a servlet wrapper. A Valve is added to a container using the <Valve> element in server.xml. They are executed in the order in which they are encountered within the server.xml file. The Tomcat distribution comes with a number of pre-rolled valves. These include: A valve that logs specific elements of a request (such as the remote client's IP address) to a log file or database A valve that lets you control access to a particular web application based on the remote client's IP address or host name A valve that lets you log every request and response header A valve that lets you configure single sign-on access across multiple web applications on a specific virtual host If these don't meet your needs, you can write your own implementations of org.apache.catalina.Valve and place them into service. A container does not hold references to individual valves. Instead, it holds a reference to a single entity known as the Pipeline, which represents a chain of valves associated with that container. When a container is invoked to process a request, it delegates the processing to its associated pipeline. The valves in a pipeline are arranged as a sequence, based on how they are defined within the server.xml file. The final valve in this sequence is known as the pipeline's basic valve. This valve performs the task that embodies the core purpose of a given container. Unlike individual valves, the pipeline is not an explicit element in server.xml, but instead is implicitly defined in terms of the sequence of valves that are associated with a given container. Each Valve is aware of the next valve in the pipeline. After it performs its pre processing, it invokes the next Valve in the chain, and when the call returns, it performs its own post processing before returning. This is very similar to what happens in filter chains within the servlet specification. In this image, the engine's configured valve(s) fire when an incoming request is received. An engine's basic valve determines the destination host and delegates processing to that host. The destination host's (www.host1.com) valves now fire in sequence. The host's basic valve then determines the destination context (here, Context1) and delegates processing to it. The valves configured for Context1 now fire and processing is then delegated by the context's basic valve to the appropriate wrapper, whose basic valve hands off processing to its wrapped servlet. The response then returns over the same path in reverse. A Valve becomes part of the Tomcat server's implementation and provides a way for developers to inject custom code into the servlet container's processing of a request. As a result, the class files for custom valves must be deployed to CATALINA_HOME/lib, rather than to the WEB-INF/classes of a deployed application. As they are not part of the servlet specification, valves are non-portable elements of your enterprise application. Therefore, if you rely on a particular valve, you will need to find equivalent alternatives in a different application server. It is important to note that valves are required to be very efficient in order not to introduce inordinate delays into the processing of a request. Realm Container managed security works by having the container handle the authentication and authorization aspects of an application. Authentication is defined as the task of ensuring that the user is who she says she is, and authorization is the task of determining whether the user may perform some specific action within an application. The advantage of container managed security is that security can be configured declaratively by the application's deployer. That is, the assignment of passwords to users and the mapping of users to roles can all be done through configuration, which can then be applied across multiple web applications without any coding changes being required to those web applications. Application Managed Security The alternative is having the application manage security. In this case, your web application code is the sole arbiter of whether a user may access some specific functionality or resource within your application. For Container managed security to work, you need to assemble the following components: Security constraints: Within your web application's deployment descriptor, web.xml, you must identify the URL patterns for restricted resources, as well as the user roles that would be permitted to access these resources. Credential input mechanism: In the web.xml deployment descriptor, you specify how the container should prompt the user for authentication credentials. This is usually accomplished by showing the user a dialog that prompts the user for a user name and password, but can also be configured to use other mechanisms such as a custom login form. Realm: This is a data store that holds user names, passwords, and roles, against which the user-supplied credentials are checked. It can be a simple XML file, a table in a relational database that is accessed using the JDBC API, or a Lightweight Directory Access Protocol (LDAP) server that can be accessed through the JNDI API. A realm provides Tomcat with a consistent mechanism of accessing these disparate data sources. All three of the above components are technically independent of each other. The power of container based security is that you can assemble your own security solution by mixing and matching selections from each of these groups. Now, when a user requests a resource, Tomcat will check to see whether a security constraint exists for this resource. For a restricted resource, Tomcat will then automatically request the user for her credentials and will then check these credentials against the configured realm. Access to the resource will be allowed only if the user's credentials are valid and if the user is a member of the role that is configured to access that resource. Executor This is a new element, available only since 6.0.11. It allows you to configure a shared thread pool that is available to all your connectors. This places an upper limit on the number of concurrent threads that may be started by your connectors. Note that this limit applies even if a particular connector has not used up all the threads configured for it. Listener Every major Tomcat component implements the org.apache.catalina.Lifecycle interface. This interface lets interested listeners to register with a component, to be notified of lifecycle events, such as the starting or stopping of that component. A listener implements the org.apache.catalina.LifecycleListener interface and implements its lifecycleEvent() method, which takes a LifecycleEvent that represents the event that has occurred. This gives you an opportunity to inject your own custom processing into Tomcat's lifecycle. Manager Sessions allows 'applications' to be made possible over the stateless HTTP protocol. A session represents a conversation between a client and a server and is implemented by a javax.servlet.http.HttpSession instance that is stored on the server and is associated with a unique identifier that is passed back by the client on each interaction. A new session is created on request and remains alive on the server either until it times out after a period of inactivity by its associated client, or until it is explicitly invalidated, for instance, by the client choosing to log out. The above image shows a very simplistic view of the session mechanism within Tomcat. An org.apache.catalina.Manager component is used by the Catalina engine to create, find, or invalidate sessions. This component is responsible for the sessions that are created for a context and their life cycles. The default Manager implementation simply retains sessions in memory, but supports session survival across server restarts. It writes out all active sessions to disk when the server is stopped and will reload them into memory when the server is started up again. A <Manager> must be a child of a <Context> element and is responsible for managing the sessions associated with that web application context. The default Manager takes attributes such as the algorithm that is used to generate its session identifiers, the frequency in seconds with which the manager should check for expired sessions, the maximum number of active sessions supported, and the file in which the sessions should be stored. Other implementations of Manager are provided that let you persist sessions to a durable data store such as a file or a JDBC database.
Read more
  • 0
  • 0
  • 4733

article-image-cms-made-simple-application-user-defined-tags
Packt
10 May 2011
9 min read
Save for later

CMS Made Simple: Application of User-Defined Tags

Packt
10 May 2011
9 min read
CMS Made Simple Development Cookbook Over 70 simple but incredibly effective recipes for extending CMS Made Simple with detailed explanations – useful for beginners and experts alike! These recipes have been specially selected to demonstrate capabilities. While they may be useful as provided, they are designed to show the range of what can be done with tags, and to provide examples of useful operations such as setting Smarty variables, interfacing with the database, interacting with modules, and consuming data from remote web services. You are encouraged to use these recipes as starting points for your own projects. Introduction One of the most popular uses of CMS Made Simple involves an administrator who creates a basic site structure and template, and one or more editors who maintain page content without having to worry about the site layout. In this configuration, you can think of the CMS essentially as a big template engine with some utilities to add content. Each page of the site comprises a page template with areas that get populated with various kinds of content. These areas are either tags or variables, where the distinction is that a tag involves the execution of code, while a variable is a simple substitution of values. The CMS comes with a large assortment of built-in tags, including the fundamental "content" tag and a variety of useful supporting tags for building navigation, links, including images, and so forth. Because CMS Made Simple can be seen as being built around tags, it is not surprising that there are facilities for creating your own tags. You can create tags directly through the Admin panel—these are called User-Defined Tags or UDTs. If you want even more extensive capabilities in your tag, you can have those capabilities by creating a file that follows a few basic conventions. The template engine used by CMS Made Simple comes from the Smarty project. Pages are Smarty templates, and the built-in CMS tag types are all Smarty tags. Behind the scenes, both UDTs and file-based tags also become Smarty tags. For additional information on Smarty, the documentation provided by the Smarty project is invaluable. You can read more at http://www.smarty.net/docsv2/en/ Displaying the User's IP address from a User-Defined Tag This recipe demonstrates creating a very simple User-Defined Tag, and using it to display information, that it gets from PHP globally-defined variables. Getting ready For this recipe, you will need to have CMS Made Simple installed and working. You will need login access to the site's Administration area as a member of the "admin" group, or as a member of a group with permissions to "Modify User-Defined Tags" and "Manage All Content". How to do it... Log in to your CMS Administration area. Using the top menu, go to "Extensions" and click on "User Defined Tags". Click on the "Add User Defined Tag" button. In the "Name" field type "user_ip". In the "Code" text area, type the following code: echo 'Welcome user from '.$_SERVER['REMOTE_ADDR'].' -- enjoy your visit!'; Click on the "Submit" button. Using the top menu, go to "Content" and click on "Pages". Click on the "Add New Content" button. In the "Title" and "Menu Text" fields, type "Tag Test". In the "Content" text area, type the following code: {user_ip} Click on the "Submit" button. View your site from the user side. Click on the new "Tag Test" page. How it works... User-Defined Tags work by linking a piece of PHP code to a tag which is recognized by Smarty. When Smarty parses a template and encounters that tag, it executes the code in question, and substitutes the tag markup with any output from that PHP code. When we create a UDT in the CMS Made Simple admin area, the name we enter into the text field becomes the tag which Smarty will look for, and the code we enter into the text area is the PHP associated with the tag. This recipe is an example of outputting text directly from a User-Defined Tag. It works by echoing a string, that then replaces the {user_ip} tag in the content. This substitution of the tag can take place either in a page template or in the page content, which might seem a little confusing since it's stated earlier that Smarty processes tags that it finds in templates. The confusion, though, is mostly due to terminology; CMS Made Simple processes both layout templates and page content through Smarty, so while it is being processed, page content serves as a template from Smarty's perspective. The User-Defined Tag we create accesses one of the PHP "superglobals"—the $_SERVER variable . This variable contains information about the HTTP request and some environmental information about the PHP server. In this case, we're getting the user's IP address information to display. Using the CmsObject and the current content object in a User-Defined Tag This recipe shows you how to access the Page Content object via the CmsObject in a User-Defined Tag. The primary technique that it demonstrates—getting a reference to the CmsObject and using the CmsObject to get a reference to other important CMS runtime objects—is one that you will use to solve many different kinds of problems. In this recipe, we use the CmsObject to get a reference to the Page Content object. Once we have a reference to this object, we can call upon its methods to report all kinds of interesting information about the current page content. Getting ready For this recipe, you will need login access to your site's Administration area with permission to "Modify User-Defined Tags" and "Manage All Content". How to do it... Log in to your CMS Administration area. Using the top menu, go to "Extensions" and click on "User Defined Tags". Click on the "Add User Defined Tag" icon. In the "Name" field, type "content_description". In the "Code" field, type the following code: $gCms = cmsms(); $contentops = $gCms->GetContentOperations(); $content_obj = $contentops->getContentObject(); echo 'Current content object is "'.$content_obj->Name().'"<br />'; echo 'which was created on '.$content_obj->GetCreationDate().'<br />'; echo 'its alias is "'.$content_obj->Alias().'"<br />'; echo 'and its URL is "'.$content_obj->GetURL().'"<br />'; Click on the "Submit" button. Using the top menu, select "Content" and click on "Pages". Click on the "Add New Content" button. Enter "New Content Page" into the "Title" and "Menu Text" fields. In the "Content" field, enter: {content_description} Click on the "Submit" button. View your site from the user side. Click on the new "Content Page" page. How it works... CMS Made Simple uses an internal object called "CmsObject" to keep track of a great deal of what it needs to serve content. This information includes the site hierarchy, the installed and active modules, references to the database, and more. The CmsObject is available to Modules, Tags, and User-Defined Tags via the cmsms() function. In this recipe, we want to display information from the current Content object. However, this object is not directly accessible. To get access to this object, we need to make a static call to the ContentOperations object, but this object is also not directly accessible from our code. To get access to these objects, we need to get references to them. We start by gaining access to the CmsObject by calling the global cmsms() function. From our reference to the CmsObject, we request a reference to the ContentOperations object, that we then use to request a reference to the current content object. Once we have the current content object, we can call assorted methods on it to retrieve information about the current content. In this recipe, we get the content's name, when it was last modified, its alias, and its URL. Since this recipe is an example, we don't format these various pieces of information or use a template, but simply echo them. In a production UDT or one in which there's any complexity to what is being displayed, it would be more advisable to use the values to populate Smarty variables for later display, or use a template for formatting them. There's more... There are a number of interesting objects, that CmsObject manages. References can be requested to: BookmarkOperations— used in the Admin area ContentOperations—which has methods to handle Content and content metadata Db— which wraps the ADODB database API GlobalContentOperations— which has methods to handle Global Content Blocks GroupOperations— which has methods to handle Admin Groups HierarchyManager— which has methods for handling site content hierarchies ModuleOperations— which has methods for managing Modules Smarty— which wraps the Smarty template engine StylesheetOperations—which has methods for handling TemplateOperations— which has methods for handling Smarty templates UserOperations— which has methods for handling Admin Users UserTagOperations— which has methods for handling User-Defined Tags Getting attributes using page_attr If you're looking to display information about the current content object, CMS Made Simple has a custom Smarty tag that provides some attributes: {page_attr}. You can use this tag to display page attribute information—simply by specifying a key to the information you're requesting. For example, to get the page's "image" attribute, you could use the tag {page_attr key="image"}. Other keys that are supported include: target image thumbnail extra1 extra2 extra3 searchable pagedata disable_wysiwyg content_en As you can see, this is not as rich a collection of information as you can get from the content object directly using your own UDT. Old code and the use of globals If you look at old modules or User-Defined Tags that have been posted in the CMS Made Simple forum, you may see the following code: global $gCms; instead of the $gCms = cmsms() used here. For a long time, the use of the global declaration was the preferred way to access the CmsObject. This approach is now deprecated for a number of reasons, most important of which is a security issue and also including portability of code between CMS Made Simple 1.x and the upcoming 2.x versions. While use of the global declaration to access the CmsObject will likely still work, it is strongly discouraged.  
Read more
  • 0
  • 0
  • 4733

article-image-program-structure-execution-flow-and-runtime-objects
Packt
30 Jul 2014
8 min read
Save for later

Program structure, execution flow, and runtime objects

Packt
30 Jul 2014
8 min read
(For more resources related to this topic, see here.) Unfortunately, C++ isn't an easy language at all. Sometimes, you can think that it is a limitless language that cannot be learned and understood entirely, but you don't need to worry about that. It is not important to know everything; it is important to use the parts that are required in specific situations correctly. Practice is the best teacher, so it's better to understand how to use as many of the features as needed. In examples to come, we will use author Charles Simonyi's Hungarian notation. In his PhD in 1977, he used Meta-Programming – A software production method to make a standard for notation in programming, which says that the first letter of type or variable should represent the data type. For the example class that we want to call, a Test data type should be CTest, where the first letter says that Test is a class. This is good practice because a programmer who is not familiar with the Test data type will immediately know that Test is a class. The same standard stands for primitive types, such as int or double. For example, iCount stands for an integer variable Count, while dValue stands for a double variable Value. Using the given prefixes, it is easy to read code even if you are not so familiar with it. Getting ready Make sure Visual Studio is up and running. How to do it... Now, let's create our first program by performing the following steps and explaining its structure: Create a new C++ console application named TestDemo. Open TestDemo.cpp. Add the following code: #include "stdafx.h" #include <iostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { cout << "Hello world" << endl; return 0; } How it works... The structure of the C++ program varies due to different programming techniques. What most programs must have is the #include or preprocessor directives. The #include <iostream> header tells the compiler to include the iostream.h header file where the available function prototypes reside. It also means that libraries with the functions' implementations should be built into executables. So, if we want to use some API or function, we need to include an appropriate header file, and maybe we will have to add an additional input library that contains the function/API implementation. One more important difference when including files is <header> versus "header". The first (<>) targets solution-configured project paths, while the other ("") targets folders relative to the C++ project. The using command instructs the compiler to use the std namespace. Namespaces are packages with object declarations and function implementations. Namespaces have a very important usage. They are used to minimize ambiguity while including third-party libraries when the same function name is used in two different packages. We need to implement a program entry point—the main function. As we said before, we can use main for an ANSI signature, wmain for a Unicode signature, or _tmain where the compiler will resolve its signature depending on the preprocessor definitions in the project property pages. For a console application, the main function can have the following four different prototypes: int _tmain(int argc, TCHAR* argv[]) void _tmain(int argc, TCHAR* argv[]) int _tmain(void) void _tmain(void) The first prototype has two arguments, argc and argv. The first argument, argc, or the argument count, says how many arguments are present in the second argument, argv, or the argument values. The argv parameter is an array of strings, where each string represents one command-line argument. The first string in argv is always the current program name. The second prototype is the same as the first one, except the return type. This means that the main function may or may not return a value. This value is returned to the OS. The third prototype has no arguments and returns an integer value, while the fourth prototype neither has arguments nor returns a value. It is good practice to use the first format. The next command uses the cout object. The cout object is the name of the standard output stream in C++, and the meaning of the entire statement is to insert a sequence of characters (in this case, the Hello world sequence of characters) into the standard output stream (usually corresponds to the screen). The cout object is declared in the iostream standard file within the std namespace. This is why we need to include the specific file and declare that we will use this specific namespace earlier in our code. In our usual selection of the (int _tmain(int,_TCHAR**)) prototype, _tmain returns an integer. We must specify some int value after the return command, in this case 0. When returning a value to the operating system, 0 usually means success, but this is operating system dependent. This simple program is very easy to create. We use this simple example to demonstrate the basic program structure and usage of the main routine as the entry point for every C++ program. Programs with one thread are executed sequentially line-by-line. This is why our program is not user friendly if we place all code into one thread. After the user gives the input, control is returned to the application. Only now can the application continue the execution. In order to overcome such an issue, we can create concurrent threads that will handle the user input. In this way, the application does not stall and is responsive all the time. After a thread handles its task, it can signal that a user has performed the requested operation to the application. There's more... Every time we have an operation that needs to be executed separately from the main execution flow, we have to think about a separate thread. The simplest example is when we have some calculations, and we want to have a progress bar where the calculation progress will be shown. If the same thread was responsible for calculation as well as to update the progress bar, probably it wouldn't work. This occurs because, if both work and a UI update are performed from a single thread, such threads can't interact with OS painting adequately; so almost always, the UI thread is separate from the working threads. Let's review the following example. Assume that we have created a function where we will calculate something, for example, sines or cosines of some angle, and we want to display progress in every step of the calculation: void CalculateSomething(int iCount) { int iCounter = 0; while (iCounter++ < iCount) { //make calculation //update progress bar } } As commands are executed one after another inside each iteration of the while loop, the operating system doesn't have the required time to properly update the user interface (in this case, the progress bar), so we would see an empty progress bar. After the function returns, a fully filled progress bar appears. The solution for this is to create a progress bar on the main thread. A separate thread should execute the CalculateSomething function; in each step of iteration, it should somehow signal the main thread to update the progress bar step by step. As we said before, threads are switched extremely fast on the CPU, so we can get the impression that the progress bar is updated at the same time at the calculation is performed. To conclude, each time we have to make a parallel task, wait for some kind of user input, or wait for an external dependency such as some response from a remote server, we will create a separate thread so that our program won't hang and be unresponsive. In our future examples, we will discuss static and dynamic libraries, so let's say a few words about both. A static library (*.lib) is usually some code placed in separate files and already compiled for future use. We will add it to the project when we want to use some of its features. When we wrote #include <iostream> earlier, we instructed the compiler to include a static library where implementations of input-output stream functions reside. A static library is built into the executable in compile time before we actually run the program. A dynamic library (*.dll) is similar to a static library, but the difference is that it is not resolved during compilation; it is linked later when we start the program, in another words—at runtime. Dynamic libraries are very useful when we have functions that a lot of programs will use. So, we don't need to include these functions into every program; we will simply link every program at runtime with one dynamic library. A good example is User32.dll, where the Windows OS placed a majority of GUI functions. So, if we create two programs where both have a window (GUI form), we do not need to include CreateWindow in both programs. We will simply link User32.dll at runtime, and the CreateWindow API will be available. Summary Thus the article covers the four main paradigms: imperative, declarative, functional (or structural), and object-oriented. Resources for Article: Further resources on this subject: OpenGL 4.0: Building a C++ Shader Program Class [Article] Application Development in Visual C++ - The Tetris Application [Article] Building UI with XAML for Windows 8 Using C [Article]
Read more
  • 0
  • 0
  • 4733

article-image-writing-tag-content
Packt
10 Jun 2014
9 min read
Save for later

Writing Tag Content

Packt
10 Jun 2014
9 min read
(For more resources related to this topic, see here.) The NDEF Message is composed by one or more NDEF records, and each record contains the payload and a header in which the data length and type and identifier are stored. In this article, we will create some examples that will allow us to work with the NDEF standard and start writing NFC applications. Working with the NDEF record Android provides an easy way to read and write data when it is formatted as per the standard NDEF. This format is the easiest way for us to work with tag data because it saves us from performing lots of operations and processes of reading and writing raw bytes. So, unless we need to get our hands dirty and write our own protocol, this is the way to go (you can still build it on top of NDEF and achieve a custom, yet standard-based protocol). Getting ready Make sure you have a working Android development environment. If you don't, ADT Bundle is a good environment to start with (you can access it by navigating to http://developer.android.com/sdk/index.html). Make sure you have an NFC-enabled Android device or a virtual test environment. It will be assumed that Eclipse is the development IDE. How to do it... We are going to create an application that writes any NDEF record to a tag by performing the following steps: Open Eclipse and create a new Android application project named NfcBookCh3Example1 with the package name nfcbook.ch3.example1. Make sure the AndroidManifest.xml file is correctly configured. Open the MainActivity.java file located under com.nfcbook.ch3.example1 and add the following class member: private NfcAdapter nfcAdapter; Implement the enableForegroundDispatch method and filter tags by using Ndef and NdefFormatable.Invoke in the onResume method: private void enableForegroundDispatch() { Intent intent = new Intent(this, MainActivity.class).addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0); IntentFilter[] intentFilter = new IntentFilter[] {}; String[][] techList = new String[][] { { android.nfc.tech.Ndef.class.getName() }, { android.nfc.tech.NdefFormatable.class.getName() } }; if ( Build.DEVICE.matches(".*generic.*") ) { //clean up the tech filter when in emulator since it doesn't work properly. techList = null; } nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFilter, techList); } Instantiate the nfcAdapter class field in the onCreate method: protected void onCreate(Bundle savedInstanceState) { ... nfcAdapter = NfcAdapter.getDefaultAdapter(this); } Implement the formatTag method: private boolean formatTag(Tag tag, NdefMessage ndefMessage) { try { NdefFormatable ndefFormat = NdefFormatable.get(tag); if (ndefFormat != null) { ndefFormat.connect(); ndefFormat.format(ndefMessage); ndefFormat.close(); return true; } } catch (Exception e) { Log.e("formatTag", e.getMessage()); } return false; } Implement the writeNdefMessage method: private boolean writeNdefMessage(Tag tag, NdefMessage ndefMessage) { try { if (tag != null) { Ndef ndef = Ndef.get(tag); if (ndef == null) { return formatTag(tag, ndefMessage); } else { ndef.connect(); if (ndef.isWritable()) { ndef.writeNdefMessage(ndefMessage); ndef.close(); return true; } ndef.close(); } } } catch (Exception e) { Log.e("formatTag", e.getMessage()); } return false; } Implement the isNfcIntent method: boolean isNfcIntent(Intent intent) { return intent.hasExtra(NfcAdapter.EXTRA_TAG); } Override the onNewIntent method using the following code: @Override protected void onNewIntent(Intent intent) { try { if (isNfcIntent(intent)) { NdefRecord ndefEmptyRecord = new NdefRecord(NdefRecord.TNF_EMPTY, new byte[]{}, new byte[]{}, new byte[]{}); NdefMessage ndefMessage = new NdefMessage(new NdefRecord[] { ndefEmptyRecord }); Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); if (writeNdefMessage(tag, ndefMessage)) { Toast.makeText(this, "Tag written!", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "Failed to write tag", Toast.LENGTH_SHORT).show(); } } } catch (Exception e) { Log.e("onNewIntent", e.getMessage()); } } Override the onPause method and insert the following code: @Override protected void onPause() { super.onPause(); nfcAdapter.disableForegroundDispatch(this); } Open the NFC Simulator tool and simulate a few tags. The tag should be marked as modified, as shown in the following screenshot: In the NFC Simulator, a tag name that ends with _LOCKED is not writable, so we won't be able to write any content to the tag and, therefore, a Failed to write tag toast will appear. How it works... NFC intents carry an extra value with them that is a virtual representation of the tag and can be obtained using the NfcAdapter.EXTRA_TAG key. We can get information about the tag, such as the tag ID and its content type, through this object. In the onNewIntent method, we retrieve the tag instance and then use other classes provided by Android to easily read, write, and retrieve even more information about the tag. These classes are as follows: android.nfc.tech.Ndef: This class provides methods to retrieve and modify the NdefMessage object on a tag android.nfc.tech.NdefFormatable: This class provides methods to format tags that are capable of being formatted as NDEF The first thing we need to do while writing a tag is to call the get(Tag tag) method from the Ndef class, which will return an instance of the same class. Then, we need to open a connection with the tag by calling the connect() method. With an open connection, we can now write a NDEF message to the tag by calling the writeNdefMessage(NdefMessage msg) method. Checking whether the tag is writable or not is always a good practice to prevent unwanted exceptions. We can do this by calling the isWritable() method. Note that this method may not account for physical write protection. When everything is done, we call the close() method to release the previously opened connection. If the get(Tag tag) method returns null, it means that the tag is not formatted as per the NDEF format, and we should try to format it correctly. For formatting a tag with the NDEF format, we use the NdefFormatable class in the same way as we did with the Ndef class. However, in this case, we want to format the tag and write a message. This is achieved by calling the format(NdefMessage firstMessage) method. So, we should call the get(Tag tag) method, then open a connection by calling connect(), format the tag, and write the message by calling the format(NdefMessage firstMessage) method. Finally, close the connection with the close() method. If the get(Tag tag) method returns null, it means that the tag is the Android NFC API that cannot automatically format the tag to NDEF. An NDEF message is composed of several NDEF records. Each of these records is composed of four key properties: Type Name Format (TNF): This property defines how the type field should be interpreted Record Type Definition (RTD): This property is used together with the TNF to help Android create the correct NDEF message and trigger the corresponding intent Id: This property lets you define a custom identifier for the record Payload: This property contains the content that will be transported to the record Using the combinations between the TNF and the RTD, we can create several different NDEF records to hold our data and even create our custom types. In this recipe, we created an empty record. The main TNF property values of a record are as follows: - TNF_ABSOLUTE_URI: This is a URI-type field - TNF_WELL_KNOWN: This is an NFC Forum-defined URN - TNF_EXTERNAL_TYPE: This is a URN-type field - TNF_MIME_MEDIA: This is a MIME type based on the type specified The main RTF property values of a record are: - RTD_URI: This is the URI based on the payload - RTD_TEXT: This is the NFC Forum-defined record type Writing a URI-formatted record URI is probably the most common content written to NFC tags. It allows you to share a website, an online service, or a link to the online content. This can be used, for example, in advertising and marketing. How to do it... We are going to create an application that writes URI records to a tag by performing the following steps. The URI will be hardcoded and will point to the Packt Publishing website. Open Eclipse and create a new Android application project named NfcBookCh3Example2. Make sure the AndroidManifest.xml file is configured correctly. Set the minimum SDK version to 14: <uses-sdk android_minSdkVersion="14" /> Implement the enableForegroundDispatch, isNfcIntent, formatTag, and writeNdefMessage methods from the previous recipe—steps 2, 4, 6, and 7. Add the following class member and instantiate it in the onCreate method: private NfcAdapter nfcAdapter; protected void onCreate(Bundle savedInstanceState) { ... nfcAdapter = NfcAdapter.getDefaultAdapter(this); } Override the onNewIntent method and place the following code: @Override protected void onNewIntent(Intent intent) { try { if (isNfcIntent(intent)) { NdefRecord uriRecord = NdefRecord.createUri("http://www.packtpub.com"); NdefMessage ndefMessage = new NdefMessage(new NdefRecord[] { uriRecord }); Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); boolean writeResult = writeNdefMessage(tag, ndefMessage); if (writeResult) { Toast.makeText(this, "Tag written!", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "Tag write failed!", Toast.LENGTH_SHORT).show(); } } } catch (Exception e) { Log.e("onNewIntent", e.getMessage()); } super.onNewIntent(intent); } Run the application. Tap a tag on your phone or simulate a tap in the NFC Simulator. A Write Successful! toast should appear. How it works... URIs are perfect content for NFC tags because with a relatively small amount of content, we can send users to more rich and complete resources. These types of records are the most easy to create, and this is done by calling the NdefRecord.createUri method and passing the URI as the first parameter. URIs are not necessarily URLs for a website. We can use other URIs that are quite well-known in Android such as the following: - tel:+000 000 000 000 - sms:+000 000 000 000 If we write the tel: uri syntax, the user will be prompted to initiate a phone call. We can always create a URI record the hard way without using the createUri method: public NdefRecord createUriRecord(String uri) { NdefRecord rtdUriRecord = null; try { byte[] uriField; uriField = uri.getBytes("UTF-8"); byte[] payload = new byte[uriField.length + 1]; //+1 for the URI prefix payload[0] = 0x00; //prefixes the URI System.arraycopy(uriField, 0, payload, 1, uriField.length); rtdUriRecord = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload); } catch (UnsupportedEncodingException e) { Log.e("createUriRecord", e.getMessage()); } return rtdUriRecord; } The first byte in the payload indicates which prefix should be used with the URI. This way, we don't need to write the whole URI in the tag, which saves some tag space. The following list describes the recognized prefixes: 0x00 No prepending is done 0x01 http://www. 0x02 https://www. 0x03 http:// 0x04 https:// 0x05 tel: 0x06 mailto: 0x07 ftp://anonymous:anonymous@ 0x08 ftp://ftp. 0x09 ftps:// 0x0A sftp:// 0x0B smb:// 0x0C nfs:// 0x0D ftp:// 0x0E dav:// 0x0F news: 0x10 telnet:// 0x11 imap: 0x12 rtsp:// 0x13 urn: 0x14 pop: 0x15 sip: 0x16 sips: 0x17 tftp: 0x18 btspp:// 0x19 btl2cap:// 0x1A btgoep:// 0x1B tcpobex:// 0x1C irdaobex:// 0x1D file:// 0x1E urn:epc:id: 0x1F urn:epc:tag: 0x20 urn:epc:pat: 0x21 urn:epc:raw: 0x22 urn:epc: 0x23 urn:nfc:
Read more
  • 0
  • 0
  • 4732

article-image-python-multimedia-working-audios
Packt
30 Aug 2010
14 min read
Save for later

Python Multimedia: Working with Audios

Packt
30 Aug 2010
14 min read
(For more resources on Python, see here.) So let's get on with it! Installation prerequisites Since we are going to use an external multimedia framework, it is necessary to install the necessary to install the packages mentioned in this section. GStreamer GStreamer is a popular open source multimedia framework that supports audio/video manipulation of a wide range of multimedia formats. It is written in the C programming language and provides bindings for other programming languages including Python. Several open source projects use GStreamer framework to develop their own multimedia application. Throughout this article, we will make use of the GStreamer framework for audio handling. In order to get this working with Python, we need to install both GStreamer and the Python bindings for GStreamer. Windows platform The binary distribution of GStreamer is not provided on the project website http://www.gstreamer.net/. Installing it from the source may require considerable effort on the part of Windows users. Fortunately, GStreamer WinBuilds project provides pre-compiled binary distributions. Here is the URL to the project website: http://www.gstreamer-winbuild.ylatuya.es The binary distribution for GStreamer as well as its Python bindings (Python 2.6) are available in the Download area of the website: http://www.gstreamer-winbuild.ylatuya.es/doku.php?id=download You need to install two packages. First, the GStreamer and then the Python bindings to the GStreamer. Download and install the GPL distribution of GStreamer available on the GStreamer WinBuilds project website. The name of the GStreamer executable is GStreamerWinBuild-0.10.5.1.exe. The version should be 0.10.5 or higher. By default, this installation will create a folder C:gstreamer on your machine. The bin directory within this folder contains runtime libraries needed while using GStreamer. Next, install the Python bindings for GStreamer. The binary distribution is available on the same website. Use the executable Pygst-0.10.15.1-Python2.6.exe pertaining to Python 2.6. The version should be 0.10.15 or higher. GStreamer WinBuilds appears to be an independent project. It is based on the OSSBuild developing suite. Visit http://code.google.com/p/ossbuild/ for more information. It could happen that the GStreamer binary built with Python 2.6 is no longer available on the mentioned website at the time you are reading this book. Therefore, it is advised that you should contact the developer community of OSSBuild. Perhaps they might help you out! Alternatively, you can build GStreamer from source on the Windows platform, using a Linux-like environment for Windows, such as Cygwin (http://www.cygwin.com/). Under this environment, you can first install dependent software packages such as Python 2.6, gcc compiler, and others. Download the gst-python-0.10.17.2.tar.gz package from the GStreamer website http://www.gstreamer.net/. Then extract this package and install it from sources using the Cygwin environment. The INSTALL file within this package will have installation instructions. Other platforms Many of the Linux distributions provide GStreamer package. You can search for the appropriate gst-python distribution (for Python 2.6) in the package repository. If such a package is not available, install gst-python from the source as discussed in the earlier the Windows platform section. If you are a Mac OS X user, visit http://py26-gst-python.darwinports.com/. It has detailed instructions on how to download and install the package Py26-gst-python version 0.10.17 (or higher). Mac OS X 10.5.x (Leopard) comes with the Python 2.5 distribution. If you are using packages using this default version of Python, GStreamer Python bindings using Python 2.5 are available on the darwinports website: http://gst-python.darwinports.com/ PyGobject There is a free multiplatform software utility library called 'GLib'. It provides data structures such as hash maps, linked lists, and so on. It also supports the creation of threads. The 'object system' of GLib is called GObject. Here, we need to install the Python bindings for GObject. The Python bindings are available on the PyGTK website at: http://www.pygtk.org/downloads.html. Windows platform The binary installer is available on the PyGTK website. The complete URL is: http://ftp.acc.umu.se/pub/GNOME/binaries/win32/pygobject/2.20/?. Download and install version 2.20 for Python 2.6. Other platforms For Linux, the source tarball is available on the PyGTK website. There could even be binary distribution in the package repository of your Linux operating system. The direct link to the Version 2.21 of PyGObject (source tarball) is: http://ftp.gnome.org/pub/GNOME/sources/pygobject/2.21/ If you are a Mac user and you have Python 2.6 installed, a distribution of PyGObject is available at http://py26-gobject.darwinports.com/. Install version 2.14 or later. Summary of installation prerequisites The following table summarizes the packages needed for this article. Package Download location Version Windows platform Linux/Unix/OS X platforms GStreamer http://www.gstreamer.net/ 0.10.5 or later Install using binary distribution available on the Gstreamer WinBuild website: http://www.gstreamer-winbuild.ylatuya.es/doku.php?id=download Use GStreamerWinBuild-0.10.5.1.exe (or later version if available). Linux: Use GStreamer distribution in package repository. Mac OS X: Download and install by following instructions on the website: http://gstreamer.darwinports.com/. Python Bindings for GStreamer http://www.gstreamer.net/ 0.10.15 or later for Python 2.6 Use binary provided by GStreamer WinBuild project. See http://www.gstreamer-winbuild.ylatuya.es for details pertaining to Python 2.6. Linux: Use gst-python distribution in the package repository. Mac OS X: Use this package (if you are using Python2.6): http://py26-gst-python.darwinports.com/. Linux/Mac: Build and install from the source tarball. Python bindings for GObject "PyGObject" Source distribution: http://www.pygtk.org/downloads.html 2.14 or later for Python 2.6 Use binary package from pygobject-2.20.0.win32-py2.6.exe Linux: Install from source if pygobject is not available in the package repository. Mac: Use this package on darwinports (if you are using Python2.6) See http://py26-gobject.darwinports.com/ for details. Testing the installation Ensure that the GStreamer and its Python bindings are properly installed. It is simple to test this. Just start Python from the command line and type the following: >>>import pygst If there is no error, it means the Python bindings are installed properly. Next, type the following: >>>pygst.require("0.10")>>>import gst If this import is successful, we are all set to use GStreamer for processing audios and videos! If import gst fails, it will probably complain that it is unable to work some required DLL/shared object. In this case, check your environment variables and make sure that the PATH variable has the correct path to the gstreamer/bin directory. The following lines of code in a Python interpreter show the typical location of the pygst and gst modules on the Windows platform. >>> import pygst>>> pygst<module 'pygst' from 'C:Python26libsite-packagespygst.pyc'>>>> pygst.require('0.10')>>> import gst>>> gst<module 'gst' from 'C:Python26libsite-packagesgst-0.10gst__init__.pyc'> Next, test if PyGObject is successfully installed. Start the Python interpreter and try importing the gobject module. >>import gobject If this works, we are all set to proceed! A primer on GStreamer In this article, we will be using GStreamer multimedia framework extensively. Before we move on to the topics that teach us various audio processing techniques, a primer on GStreamer is necessary. So what is GStreamer? It is a framework on top of which one can develop multimedia applications. The rich set of libraries it provides makes it easier to develop applications with complex audio/video processing capabilities. Fundamental components of GStreamer are briefly explained in the coming sub-sections. Comprehensive documentation is available on the GStreamer project website. GStreamer Application Development Manual is a very good starting point. In this section, we will briefly cover some of the important aspects of GStreamer. For further reading, you are recommended to visit the GStreamer project website: http://www.gstreamer.net/documentation/ gst-inspect and gst-launch We will start by learning the two important GStreamer commands. GStreamer can be run from the command line, by calling gst-launch-0.10.exe (on Windows) or gst-launch-0.10(on other platforms). The following command shows a typical execution of GStreamer on Linux. We will see what a pipeline means in the next sub-section. $gst-launch-0.10 pipeline_description GStreamer has a plugin architecture. It supports a huge number of plugins. To see more details about any plugin in your GStreamer installation, use the command gst-inspect-0.10 (gst-inspect-0.10.exe on Windows). We will use this command quite often. Use of this command is illustrated here. $gst-inspect-0.10 decodebin Here, decodebin is a plugin. Upon execution of the preceding command, it prints detailed information about the plugin decodebin. Elements and pipeline In GStreamer, the data flows in a pipeline. Various elements are connected together forming a pipeline, such that the output of the previous element is the input to the next one. A pipeline can be logically represented as follows: Element1 ! Element2 ! Element3 ! Element4 ! Element5 Here, Element1 through to Element5 are the element objects chained together by the symbol !. Each of the elements performs a specific task. One of the element objects performs the task of reading input data such as an audio or a video. Another element decodes the file read by the first element, whereas another element performs the job of converting this data into some other format and saving the output. As stated earlier, linking these element objects in a proper manner creates a pipeline. The concept of a pipeline is similar to the one used in Unix. Following is a Unix example of a pipeline. Here, the vertical separator | defines the pipe. $ls -la | more Here, the ls -la lists all the files in a directory. However, sometimes, this list is too long to be displayed in the shell window. So, adding | more allows a user to navigate the data. Now let's see a realistic example of running GStreamer from the command prompt. $ gst-launch-0.10 -v filesrc location=path/to/file.ogg ! decodebin ! audioconvert ! fakesink For a Windows user, the gst command name would be gst-launch-0.10.exe. The pipeline is constructed by specifying different elements. The !symbol links the adjacent elements, thereby forming the whole pipeline for the data to flow. For Python bindings of GStreamer, the abstract base class for pipeline elements is gst.Element, whereas gst.Pipeline class can be used to created pipeline instance. In a pipeline, the data is sent to a separate thread where it is processed until it reaches the end or a termination signal is sent. Plugins GStreamer is a plugin-based framework. There are several plugins available. A plugin is used to encapsulate the functionality of one or more GStreamer elements. Thus we can have a plugin where multiple elements work together to create the desired output. The plugin itself can then be used as an abstract element in the GStreamer pipeline. An example is decodebin. We will learn about it in the upcoming sections. A comprehensive list of available plugins is available at the GStreamer website http://gstreamer.freedesktop.org. In almost all applications to be developed, decodebin plugin will be used. For audio processing, the functionality provided by plugins such as gnonlin, audioecho, monoscope, interleave, and so on will be used. Bins In GStreamer, a bin is a container that manages the element objects added to it. A bin instance can be created using gst.Bin class. It is inherited from gst.Element and can act as an abstract element representing a bunch of elements within it. A GStreamer plugin decodebin is a good example representing a bin. The decodebin contains decoder elements. It auto-plugs the decoder to create the decoding pipeline. Pads Each element has some sort of connection points to handle data input and output. GStreamer refers to them as pads. Thus an element object can have one or more "receiver pads" termed as sink pads that accept data from the previous element in the pipeline. Similarly, there are 'source pads' that take the data out of the element as an input to the next element (if any) in the pipeline. The following is a very simple example that shows how source and sink pads are specified. >gst-launch-0.10.exe fakesrc num-bufferes=1 ! fakesink The fakesrc is the first element in the pipeline. Therefore, it only has a source pad. It transmits the data to the next linkedelement, that is fakesink which only has a sink pad to accept elements. Note that, in this case, since these are fakesrc and fakesink, just empty buffers are exchanged. A pad is defined by the class gst.Pad. A pad can be attached to an element object using the gst.Element.add_pad() method. The following is a diagrammatic representation of a GStreamer element with a pad. It illustrates two GStreamer elements within a pipeline, having a single source and sink pad. Now that we know how the pads operate, let's discuss some of special types of pads. In the example, we assumed that the pads for the element are always 'out there'. However, there are some situations where the element doesn't have the pads available all the time. Such elements request the pads they need at runtime. Such a pad is called a dynamic pad. Another type of pad is called ghost pad. These types are discussed in this section.   Dynamic pads Some objects such as decodebin do not have pads defined when they are created. Such elements determine the type of pad to be used at the runtime. For example, depending on the media file input being processed, the decodebin will create a pad. This is often referred to as dynamic pad or sometimes the available pad as it is not always available in elements such as decodebin. Ghost pads As stated in the Bins section a bin object can act as an abstract element. How is it achieved? For that, the bin uses 'ghost pads' or 'pseudo link pads'. The ghost pads of a bin are used to connect an appropriate element inside it. A ghost pad can be created using gst.GhostPad class. Caps The element objects send and receive the data by using the pads. The type of media data that the element objects will handle is determined by the caps (a short form for capabilities). It is a structure that describes the media formats supported by the element. The caps are defined by the class gst.Caps. Bus A bus refers to the object that delivers the message generated by GStreamer. A message is a gst.Message object that informs the application about an event within the pipeline. A message is put on the bus using the gst.Bus.gst_bus_post() method. The following code shows an example usage of the bus. 1 bus = pipeline.get_bus()2 bus.add_signal_watch()3 bus.connect("message", message_handler) The first line in the code creates a gst.Bus instance. Here the pipeline is an instance of gst.PipeLine. On the next line, we add a signal watch so that the bus gives out all the messages posted on that bus. Line 3 connects the signal with a Python method. In this example, the message is the signal string and the method it calls is message_handler. Playbin/Playbin2 Playbin is a GStreamer plugin that provides a high-level audio/video player. It can handle a number of things such as automatic detection of the input media file format, auto-determination of decoders, audio visualization and volume control, and so on. The following line of code creates a playbin element. playbin = gst.element_factory_make("playbin") It defines a property called uri. The URI (Uniform Resource Identifier) should be an absolute path to a file on your computer or on the Web. According to the GStreamer documentation, Playbin2 is just the latest unstable version but once stable, it will replace the Playbin. A Playbin2 instance can be created the same way as a Playbin instance. gst-inspect-0.10 playbin2 With this basic understanding, let us learn about various audio processing techniques using GStreamer and Python.
Read more
  • 0
  • 0
  • 4728

article-image-abstract-terrain-shader-duality
Lőrinc Serfőző
06 Jan 2017
5 min read
Save for later

Abstract terrain shader in Duality

Lőrinc Serfőző
06 Jan 2017
5 min read
This post guides you through the creation process of abstract-looking terrain shaders in the Duality 2D game engine. The basics of the engine are not presented here, but if you are familiar with game technology, it should not be too difficult to follow along. If something does not make sense at first, take a look at the official documentation on GitHub. Alternatively, there are two tutorials with more of an introductory flair. In addition, the concepts described here can be easily adapted to other game engines and frameworks as well. Required tools Duality can be downloaded from the official site. A C# compiler and a text editor are also needed. Visual Studio 2013 or higher is recommended, but other IDEs, like MonoDevelop also work. Creating the required resources Open up a new project in Dualitor! First, we have to create several new resources. The following list describes the required resources. Create and name them accordingly. VertexShader encapsulates a GLSL vertex shader. We need this, because the vertex coordinates should be converted to world space, in order to achieve the desired terrain effect. More on that later. FragmentShader encapsulates a GLSL fragment shader, the 'creative' part of our processing. ShaderProgram binds a VertexShader and a FragmentShader together. DrawTechnique provides attributes (such as blending mode, etc.) to the ShaderProgram to be able to send it to the GPU. Material establishes the connection between a DrawTechnique and one or several textures and other numerical data. It can be attached to the GameObject's renderers in the scene. The vertex shader Let's start with implementing the vertex shader. Unlike most game engines, Duality handles some of the vertex transformations on the CPU, in order to achieve a parallax scaling effect. Thus, the vertex array passed to the GPU is already scaled. However, we do not need that precalculation for our terrain shader, so this transformation has to be undone in the vertex shader. Double click the VertexShader resource to open it in an external text editor. It should contain the following: void main() { gl_Position = ftransform(); gl_TexCoord[0] = gl_MultiTexCoord0; gl_FrontColor = gl_Color; } To perform the inverse transformation, the camera data should be passed to the shader. This is done automatically by Duality via pre-configured uniform variables: CameraFocusDist, CameraParallax and CameraPosition. The result worldPosition is passed to the fragment shader via a varying variable. // vertex shader varying vec3 worldPosition; uniform float CameraFocusDist; uniform bool CameraParallax; uniform vec3 CameraPosition; vec3 reverseParallaxTransform () { // Duality uses software pre-transformation of vertices // gl_Vertex is already in parallax (scaled) view space when arriving here. vec4 vertex = gl_Vertex; // Reverse-engineer the scale that was previously applied to the vertex float scale = 1.0; if (CameraParallax) { scale = CameraFocusDist / vertex.z; } else { // default focus dist is 500 scale = CameraFocusDist / 500.0; } return vec3 (vertex.xyz + vec3 (CameraPosition.xy, 0)) / scale; } void main() { gl_Position = ftransform(); gl_TexCoord[0] = gl_MultiTexCoord0; gl_FrontColor = gl_Color; worldPosition = reverseParallaxTransform (); } The fragment shader Next, implement the fragment shader. Various effects can be achieved using textures and mathematical functions creatively. Here a simple method is presented: the well-known XOR texture generation. It is based on calculating the binary exclusive or product of the integer world coordinates (operator ^ in GLSL). To control its parameters, two uniform variables, scale and repeat, are introduced in addition to the varying one from the vertex shader. A texture named mainTex is also used to alpha-mask the product. // fragment shader varying vec3 worldPosition; uniform float scale; uniform int repeat; uniform sampler2D mainTex; void main() { vec4 texSample = texture2D(mainTex, gl_TexCoord[0].st); int x = (int)(worldPosition.x * scale) % repeat; int y = (int)(worldPosition.y * scale) % repeat; vec3 color = gl_Color.rgb * (x ^ y) / (float)repeat; gl_FragColor = vec4(color, 1.0) * texSample.a; } Assign the VertexShader and FragmentShader resources to the ShaderProgram resource, and that to the DrawTechnique resource. The latter one, as mentioned, determines the blending mode. This time it has to be set to Mask in order to make the alpha masking work. The DrawTechnique should be assigned to the Material resource. The material is used to control the custom uniform parameters. The following values yield correct results: MainColor: Anything but black or white for testing purposes. mainTex: A texture with alpha mask. For example, this rounded block shape. scale: 1.0. repeat: 256. Populating the scene Create a SpriteRenderer in the scene, and assign the new material to it. Because we used world coordinates in the fragment shader, the texture stays fixed relative to the world, and the alpha mask functions as a “window” to it. The effect can be perceived by repositioning the sprite in the game world. Duplicate the sprite GameObject several times and move them around. When they intersect, the texture should be perfectly continuous. You may notice that the texture behaves incorrectly while moving the camera in Scene Editor view. The reason behind is that in that view mode, the camera is different than the one the shader calculates against. For inspecting the final look, use the Game View. Summary This technique can be used to quickly build continuous-looking terrains using a small number of alpha masks in your top-down or sidescroller game projects. Of course, the fragment shader could be extended with additional logic and textures. Experimenting with them often yields usable results. I hope you enjoyed this post. In case you have any questions, feel free to post them below, or on the Duality forums. About the author Lőrinc Serfőző is a software engineer at Graphisoft, the company behind the the BIM solution ArchiCAD. He is studying mechatronics engineering at the Budapest University of Technology and Economics. It’s an interdisciplinary field between the more traditional mechanical engineering, electrical engineering and informatics, and Lőrinc has quickly grown a passion toward software development. He is a supporter of open source software and contributes to the C# and OpenGL-based Duality game engine, creating free plugins and tools for users.
Read more
  • 0
  • 0
  • 4726
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-gateways-sipxecs-40-part-2
Packt
21 Oct 2009
5 min read
Save for later

Gateways in sipXecs 4.0: Part 2

Packt
21 Oct 2009
5 min read
Advanced Parameters The Advanced Parameters settings, shown as follows, are accessed by clicking on the Advanced Parameters item in the lefthand menu and are a collection of AudiCodes-specific settings. The following configuration options are available on this page (click on Show Advanced Settings to reveal all options): Secure SIP Calls: If this is enabled, gateways will only accept SIP calls from IP addresses listed below. The default is disabled (unchecked) Accepted IP Addresses: They are used in conjunction with the above setting. It is a space-separated list of IP addresses from which gateway will accept the calls. It is taken into account only if Secure SIP Calls is enabled. The default is the IP address provided for the PBX during install. Digit Delivery to Telephony Port: This setting enables a digit string to be played to the port at the far end, after off-hook. The default is disabled (unchecked). Digit Delivery to IP: This setting enables a digit string to be played to the port at the far end, after off-hook. The default is disabled (unchecked). DID Wink Support: When this is enabled, the gateway can connect to EIA/TIA 464B Loop Start DID lines. Both generation and detection are supported. The default setting is disabled (unchecked). Enable Call Disconnect on Polarity Reversal: If this is checked, enables port disconnect (on-hook) based on polarity reversal. Some POTS providers will reverse the polarity of the analog phone line to signal disconnection to a PBX. The default is disabled (unchecked). Enable Call Disconnect on Current Drop: If this is set to 1, enables port disconnect (on-hook) based on current drop. The default setting is disabled (0). Enable Call Disconnect on Broken Connection: If this is checked, the call is released if the gateway stops receiving RTP for a period of time. The default is enabled (checked). Broken Connection Timeout (10msec): The amount of time for which RTP is not received, before the call is cleared. In 10 ms steps, the default is 500, 10 ms steps (5 seconds). Enable Call Disconnect on Far End Silence: If this checked, enables disconnection of call based on silence. The default is disabled (unchecked). Silence Period for Disconnect: The detection period, in seconds, before the call is released based on silence. The default is 120 seconds. Silence Detection Method: This setting can be set to "None" (silence detection option is disabled), "Packets Count" (according to packet count), "Voice/Energy Detectors" (according to energy and voice detectors (default)) or "All" (according to packet count and energy / voice detectors). Silence Threshold: The threshold of packet count, in percentage, below which is considered as silence. The default setting is 8 packets. Detail Level in Debug Log: The detail level of the log messages sent to syslog server. Default is 0 (off), max is 5 (full). CDR Server IP Address: An optional separate syslog server to collect CDRs only. If null and CDR is enabled, the output is mixed with the log messages and is routed to the syslog server IP. (Default: 0.0.0.0) CDR Report Level: This can be set to "None", (Call Detail Recording or CDR information isn't sent to the Syslog server, which is the default value), "End Call" (CDR information is sent to the Syslog server at the end of each Call) and, "Start & End Call" (CDR information is sent to the Syslog server at the start and at the end of each Call). Port Busy-Out Method  : If there is a network-side failure on the gateway, the POTS interfaces can be set to busy. If this is  checked, telephony ports are busied out (special tone) in case of LAN failure or proxy communication failure. The default is disabled (unchecked). Delay After Reset [sec]: Amount of time delay before answering calls after gateway reset. The default is 7 seconds. Max Number of Active Calls: This is the maximum number of active calls the PBX can process. It should be set to the number of PSTN lines active. Max Call Duration [min]: This is the maximum duration of a phone call. The default is 0, which means no maximum. Enable LAN Watchdog: When LAN Watchdog is enabled, the gateway's overall communication integrity is checked periodically. If no communication for about 3 minutes is detected, the gateway performs a self test. If the self test succeeds, the problem is logical link down (for example, Ethernet cable disconnected on the switch side), and the "Busy Out" mechanism is activated if enabled (EnableBusyOut = 1). Lifeline is activated if enabled. If the self test fails, the gateway restarts to overcome an internal fatal communication error (default: unchecked). Enable SAS: This setting is to enable/disable Stand-Alone Survivability (SAS) (default: unchecked). • SAS Registration Time: This is the time after which SAS is enabled (default: 20 seconds). SAS Local SIP UDP port: This is the UDP Port for SAS SIP signaling (default: 5080). SAS Local SIP TCP port: This is the TCP Port for SAS SIP signaling (default: 5080). SAS Local SIP TLS port: This is the TLS Port for SAS SIP signaling (default: 5081). SAS Default Gateway: This is the SAS Default Gateway IP address (default blank). SAS Short Number Length: This is the SAS short number length. Click on the Apply button to keep any changes made on this page.
Read more
  • 0
  • 0
  • 4725

article-image-triggers-zabbix-18
Packt
29 Mar 2010
8 min read
Save for later

Triggers in Zabbix 1.8

Packt
29 Mar 2010
8 min read
Triggers are things that "fire". They are the ones that look at item data and raise a flag when the data does not fit whatever condition is defined. As we discussed before, simply gathering data is nice, but awfully inadequate. If you want anything past historical data gathering, including notifications—there would have to be a person looking at all the data all the time, so we have to define thresholds at which we want the condition to be considered worth looking into. Triggers provide a way to define what those conditions are. Earlier, we created a single trigger that was checking the system load on "A Test Host". It checks whether the returned value is larger than a defined threshold. Now, let's check for some other possible problems with a server—for example, when a service is down. The SMTP service going down can be significant, so we will try to look for such an event now. Navigate to Configuration | Hosts, choose Triggers in the first dropdown and click on the Create Trigger button. In the form that opens, we will fill in some values. Name: The contents of this field will be used to identify the trigger in most places, so it should be human-readable. This time, enter SMTP service is down. Notice how we are describing what the problem actually is. As opposed to an item, which is gathering statuses, a trigger has a specific condition to check, thus the name reflects it. If we had a host that should not ever have a running SMTP service, we could create a trigger named "SMTP service should not be running". Expression: This is probably the most important factor of a trigger. What is being checked, and for what conditions, will be specified here. Trigger expressions can vary from very simple to complex ones. This time we will create a simple one, and we will also use some help with that. Click the Select button next to the Expression fi eld to open expression building dialog. It has several fields to fill as well, so let's look at what those are. Item: Here, we can specify which item data should be checked. To do that click on the Select button. Another pop up opens. Select Linux servers in the Group dropdown, then select Another Host in the Host dropdown. We are interested in the SMTP service, so click on SMTP server status in the Description column. Pop up will close, and Item field will be populated with the chosen name. Function: Here we can choose the actual check to be performed. Maybe we can try remembering what the SMTP server status item values were—right, "1" was for server running, and "0" was for server down. If we want to check whenever the last value is 0, the default function seems to fit quite nicely, so we won't change it. N: This field allows us to set the constant used in the function above. We want to find out whenever server goes down (or status is "0"), so here the default fits as well. With the values set as above, click the Insert button. Expression field is now populated with a trigger expression {Another Host:smtp.last(0)}=0. Severity: There are five severity levels in Zabbix, and an additional "Not classified" severity. We will consider this problem to be of an average severity, so choose Average from the dropdown Before continuing, make sure the SMTP server is running on "Another Host", then click Save. Let's find out how it looks in the overview now—open Monitoring | Overview and make sure Type dropdown has Triggers selected. Great, we can see both hosts now have a trigger defined. As the triggers differ, we also have two unused cells. A newly added trigger will be flashing, thus indicating a recent change. Let's look at the trigger expression in more detail. It starts with an opening curly brace, and the first parameter is the hostname. Separated with a colon is the item key—smtp here. After the dot comes the more interesting and trigger specific thing—the trigger function. Used here is one of the most common functions, last. It always returns single value from the item history. Here it also has a parameter passed, 0, enclosed in parenthesis. For this particular function, a parameter passed with such syntax is ignored, while it could mean seconds, that would not make much sense (the function returns a single value only). Still, a parameter has to be provided even for functions that ignore it. But that's not the only parameter syntax this function supports—if the value is prefixed with a hash, it is not ignored. In that case it works like an Nth value  specifier. For example, last(#9) would retrieve the 9th most recent value. As wecan see, last(#1) is equal to last(0). Another overlapping function is prev. As the name might suggest, it returns the previous value, thus prev(0) is the same as last(#2). Continuing with the trigger expression, curly braces close to represent a string that retrieves some value. Then we have an operator, which in this case is a simple equal sign. Comparison is done with a constant number, zero. Trigger dependencies We now have one service being watched. Though there are some more monitored and now we can try to create a trigger for a HTTP server. Go to Configuration | Hosts, click on Triggers next to Another Host, then click on Create Trigger. Fill in the following values: Name: Enter WEB service is down. Expression: Click on Select, then again on Select next to the Item field. Make sure Linux servers is selected in the Group field and Another Host in the host field, then click on WEB server status in the Description column. Both function and its parameter are fine, so click on Insert. That inserts the expression {Another Host:net.tcp.service[http,,80]. last(0)}=0. The trigger depends on: Our host runs software that is a bit weird—the web service is a web e-mail frontend, and it goes down whenever the SMTP server is unavailable. This means the web service depends on SMTP service. To configure that, click on Add next to the New dependency. In the resulting window, make sure Linux servers is selected in the Group dropdown and Another Host is selected in the Host dropdown, then click on the only entry in the Description column—SMTP service is down. Severity: Select Average. Comments: Trigger expressions can get very complex. Sometimes the complexity can make it impossible to understand what a trigger is supposed to do without serious dissection. Comments provide a way to help somebody else, or yourself, to understand the thinking behind such complex triggers later. While our trigger still is very simple, we might want to explain the reason for the dependency, so enter something like Web service goes down if SMTP is inaccessible. When you are done, click Save. Notice how, in the trigger list, trigger dependencies are listed in the Name column. This allows for a quick overview of any dependent triggers without opening the details of each trigger individually. With the dependency set up, let's find out whether it changes anything in the frontend. Navigate to Monitoring | Overview. Indeed, the difference is visible immediately. Triggers involved in the dependency have arrows drawn over them. So an upwards arrow means something depends on this trigger or was it the other way around? Luckily, you don't have to memorize that. Move the mouse cursor over the SMTP service is down trigger for Another Host, the upper cell with the arrow. A pop up appears, informing you that there are other triggers dependent on this one. Dependent triggers are listed in the pop up. Now move the mouse cursor one cell below, over the downwards pointing arrow. Let's see what effect other than the arrows does this provide. Open Monitoring | Triggers and make sure both Host and Group dropdowns say all, then bring down web server on "Another Host". Wait for the trigger to fire, look at the entry. Notice how an arrow indicating dependency is displayed here as well. Move the mouse cursor over it again, and the dependency details are displayed in a pop up. Hey, what's up with the Show link in the Comments column? Let's find out—click on it. As can be seen, the comment we provided when creating the trigger is displayed. This allows for easy access to comments from the trigger list both for finding out more information about the trigger and updating the comment as well. Click on Cancel to return to the trigger list. Now, stop the SMTP service on the "Another Host".
Read more
  • 0
  • 0
  • 4725

article-image-templates-web-pages
Packt
13 Oct 2015
13 min read
Save for later

Templates for Web Pages

Packt
13 Oct 2015
13 min read
In this article, by Kai Nacke, author of the book D Web Development, we will learn that every website has some recurring elements, often called a theme. Templates are an easy way to define these elements only once and then reuse them. A template engine is included in vibe.dwith the so-called Diet templates. The template syntax is based on the Jade templates (http://jade-lang.com/), which you might already know about. In this article, you will learn the following: Why are templates useful Key concepts of Diet templates: inheritance, include and blocks How to use filters and how to create your own filter (For more resources related to this topic, see here.) Using templates Let's take a look at the simple HTML5 page with a header, footer, navigation bar and some content in the following: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Demo site</title> <link rel="stylesheet" type="text/css" href="demo.css" /> </head> <body> <header> Header </header> <nav> <ul> <li><a href="link1">Link 1</a></li> <li><a href="link2">Link 2</a></li> <li><a href="link3">Link 3</a></li> </ul> </nav> <article> <h1>Title</h1> <p>Some content here.</p> </article> <footer> Footer </footer> </body> </html> The formatting is done with a CSS file, as shown in the following: body { font-size: 1em; color: black; background-color: white; font-family: Arial; } header { display: block; font-size: 200%; font-weight: bolder; text-align: center; } footer { clear: both; display: block; text-align: center; } nav { display: block; float: left; width: 25%; } article { display: block; float: left; } Despite being simple, this page has elements that you often find on websites. If you create a website with more than one page, then you will use this structure on every page in order to provide a consistent user interface. From the 2nd page, you will violate the Don't Repeat Yourself(DRY) principle: the header and footer are the elements with fixed content. The content of the navigation bar is also fixed but not every item is always displayed. Only the real content of the page (in the article block) changes with every page. Templates solve this problem. A common approach is to define a base template with the structure. For each page, you will define a template that inherits from the base template and adds the new content. Creating your first template In the following sections, you will create a Diet template from the HTML page using different techniques. Turning the HTML page into a Diet template Let's start with a one-to-one translation of the HTML page into a Diet template. The syntax is based on the Jade templates. It looks similar to the following: doctype html html head meta(charset='utf-8') title Demo site link(rel='stylesheet', type='text/css', href='demo.css') body header | Header nav ul li a(href='link1') Link 1 li a(href='link2') Link 2 li a(href='link3') Link 3 article h1 Title p Some content here. footer | Footer The template resembles the HTML page. Here are the basic syntax rules for a template: The first word on a line is an HTML tag Attributes of an HTML tag are written as a comma-separated list surrounded by parenthesis A tag may be followed by plain text that may contain the HTML code Plain text on a new line starts with the pipe symbol Nesting of elements is done by increasing the indentation. If you want to see the result of this template, save the code as index.dt and put it together with the demo.css CSS file in the views folder. The Jade templates have a special syntax for the nested elements. The list item/anchor pair from the preceding code could be written in one line, as follows: li: a(href='link1') Link1 This syntax is currently not supported by vibe.d. Now, you need to create a small application to see the result of the template by following the given steps: Create a new project template with dub, using the following command: $ dub init template vibe.d Save the template as the views/index.dt file. Copy the demo.css CSS file in the public folder. Change the generated source/app.d application to the following: import vibe.d; shared static this() { auto router = new URLRouter; router.get("/", staticTemplate!"index.dt"); router.get("*", serveStaticFiles("public/")); auto settings = new HTTPServerSettings; settings.port = 8080; settings.bindAddresses = ["::1", "127.0.0.1"]; listenHTTP(settings, router); logInfo("Please open http://127.0.0.1:8080/ in your browser."); } Run dub inside the project folder to start the application and then browse to http://127.0.0.1:8080/ to see the resulting page. The application uses a new URLRouter class. This class is used to map a URL to a web page. With the router.get("/", staticTemplate!"index.dt");statement, every request for the base URL is responded with rendering of the index.dt template. The router.get("*", serveStaticFiles("public/")); statement uses a wild card to serve all other requests as static files that are stored in the public folder. Adding inheritance Up to now, the template is only a one-to-one translation of the HTML page. The next step is to split the file into two, layout.dt and index.dt. The layout.dtfile defines the general structure of a page while index.dt inherits from this file and adds new content. The key to template inheritance is the definition of a block. A block has a name and contains some template code. A child template may replace the block, append, or prepend the content to a block. In the following layout.dt file, four blocks are defined: header, navigation, content and footer. For all the blocks, except content, a default text is defined, as follows: doctype html html head meta(charset='utf-8') title Demo site link(rel='stylesheet', type='text/css', href='demo.css') body block header header Header block navigation nav ul li <a href="link1">Link 1</a> li <a href="link2">Link 2</a> li <a href="link3">Link 3</a> block content block footer footer Footer The template in the index.dt file inherits this layout and replaces the block content, as shown here: extends layout block content article h1 Title p Some content here. You can put both the files into the views folder and run dub again. The rendered page in your browser still looks the same. You can now add more pages and reuse the layout. It is also possible to change the common elements that you defined in the header, footer and navigation blocks. There is no restriction on the level of inheritance. This allows you to construct very sophisticated template systems. Using include Inheritance is not the only way to avoid repetition of template code. With the include keyword, you insert the content of another file. This allows you to put the reusable template code in separate files. As an example, just put the following navigation in a separate navigation.dtfile: nav     ul         li <a href="link1">Link 1</a>         li <a href="link2">Link 2</a>         li <a href="link3">Link 3</a> The index.dt file uses the include keyword to insert the navigation.dt file, as follows: doctype html html     head        meta(charset='utf-8')         title Demo site         link(rel='stylesheet', type='text/css', href='demo.css')     body         header Header         include navigation         article             h1 Title             p Some content here.         footer Footer Just as with the inheritance example, you can put both the files into the views folder and run dub again. The rendered page in your browser still looks the same. The Jade templates allow you to apply a filter to the included content. This is not yet implemented. Integrating other languages with blocks and filters So far, the templates only used the HTML content. However, a web application usually builds on a bunch of languages, most often integrated in a single document, as follows: CSS styles inside the style element JavaScript code inside the script element Content in a simplified markup language such as Markdown Diet templates have two mechanisms that are used for integration of other languages. If a tag is followed by a dot, then the block is treated as plain text. For example, the following template code: p. Some text And some more text It translates into the following: <p>     Some text     And some more text </p> The same can also be used for scripts and styles. For example, you can use the following script tag with the JavaScript code in it: script(type='text/javascript').     console.log('D is awesome') It translates to the following: <script type="text/javascript"> console.log('D is awesome') </script> An alternative is to use a filter. You specify a filter with a colon that is followed by the filter name. The script example can be written with a filter, as shown in the following: :javascript     console.log('D is awesome') This is translated to the following: <script type="text/javascript">     //<![CDATA[     console.log('D is aewsome')     //]]> </script> The following filters are provided by vibe.d: javascript for JavaScript code css for CSS styles markdown for content written in Markdown syntax htmlescapeto escape HTML symbols The css filter works in the same way as the javascript filter. The markdown filter accepts the text written in the Markdown syntax and translates it into HTML. Markdown is a simplified markup language for web authors. The syntax is available on the internet at http://daringfireball.net/projects/markdown/syntax. Here is our template, this time using the markdown filter for the navigation and the article content: doctype html html     head         meta(charset='utf-8')         title Demo site         link(rel='stylesheet', type='text/css', href='demo.css')     body        header Header         nav             :markdown                 - [Link 1](link1)                 - [Link 2](link2)                 - [Link 3](link3)         article             :markdown                 Title                 =====                 Some content here.         footer Footer The rendered HTML page is still the same. The advantage is that you have less to type, which is good if you produce a lot of content. The disadvantage is that you have to remember yet another syntax. A normal plain text block can contain HTML tags, as follows: p. Click this <a href="link">link</a> This is rendered as the following: <p>     Click this <a href="link">link</a> </p> There are situations where you want to even treat the HTML tags as plain text, for example, if you want to explain HTML syntax. In this case, you use the htmlescape filter, as follows: p     :htlmescape         Link syntax: <a href="url target">text to display</a> This is rendered as the following: <p>     Link syntax: &lt;a href="url target"&gt;text to display&lt;/a&gt; </p> You can also add your owns filters. The registerDietTextFilter()function is provided by vibe.d to register the new filters. This function takes the name of the filter and a pointer to the filter function. The filter function is called with the text to filter and the indentation level. It returns the filtered text. For example, you can use this functionality for pretty printing of D code, as follows: Create a new project with dub,using the following command: $ dub init filter vibe.d Create the index.dttemplate file in the viewsfolder. Use the new dcodefilter to format the D code, as shown in the following: doctype html head title Code filter example :css .keyword { color: #0000ff; font-weight: bold; } body p You can create your own functions. :dcode T max(T)(T a, T b) { if (a > b) return a; return b; } Implement the filter function in the app.dfile in the sourcefolder. The filter function outputs the text inside a <pre> tag. Identified keywords are put inside the <span class="keyword"> element to allow custom formatting. The whole application is as follows: import vibe.d; string filterDCode(string text, size_t indent) { import std.regex; import std.array; auto dst = appender!string; filterHTMLEscape(dst, text, HTMLEscapeFlags.escapeQuotes); auto regex = regex(r"(^|s)(if|return)(;|s)"); text = replaceAll(dst.data, regex, "$1<span class="keyword">$2</span>$3"); auto lines = splitLines(text); string indent_string = "n"; while (indent-- > 0) indent_string ~= "t"; string ret = indent_string ~ "<pre>"; foreach (ln; lines) ret ~= indent_string ~ ln; ret ~= indent_string ~ "</pre>"; return ret; } shared static this() { registerDietTextFilter("dcode", &filterDCode); auto settings = new HTTPServerSettings; settings.port = 8080; settings.bindAddresses = ["::1", "127.0.0.1"]; listenHTTP(settings, staticTemplate!"index.dt"); logInfo("Please open http://127.0.0.1:8080/ in your browser."); } Compile and run this application to see that the keywords are bold and blue. Summary In this article, we have seen how to create a Diet template using different techniques such as translating the HTML page into a Diet template, adding inheritance, using include, and integrating other languages with blocks and filters. Resources for Article: Further resources on this subject: MODx Web Development: Creating Lists [Article] MODx 2.0: Web Development Basics [Article] Ruby with MongoDB for Web Development [Article]
Read more
  • 0
  • 0
  • 4721

article-image-using-graphs-manage-networks-and-devices-cacti-08
Packt
16 Oct 2009
4 min read
Save for later

Using Graphs to Manage Networks and Devices with Cacti 0.8

Packt
16 Oct 2009
4 min read
Creating graphs If you are familiar with RRDTool, then you know Cacti is designed to harness the power of RRDTool's data storage and graphing functionality. If you are not, don't worry—Cacti will create graphs without extensive configuration input from users. Built-in graph templates will make your life easier, so it is not necessary to understand the functionality of each field to create graphs for network-attached devices. Each graph stores different sets of parameters that control different aspects of each graph. If you want to know more about RRDTool, please visit http://oss.oetiker.ch/rrdtool/. At the time of creating graphs, you will face a bit of a stiff learning curve. Stay on course, it will be over soon and you will be able to create graphs for different devices very quickly. Cacti can create graphs for any SNMP-enabled, network-attached devices. This can be a switch, router, server, desktop computer, printer, IPS, UPS, and so on. Initially, we will not talk about the custom template and the data-query script development for any SNMP-enabled devices. Instead, we will use the default options in Cacti. In order to build a custom template, we need to understand the SNMP protocol and command-line tools of the Net-SNMP application suite. Let's create graphs based on the available templates and devices. Adding a device Before we add a graph, we need to add a device for which you want to create the graph. In order to do that, click on Devices under Management. Cacti will open the Devices view panel. It will look like this: If you click Add in the top right-hand corner, it will open a new form to add a new device. The first two fields, Description and Hostname, are both required for the default configuration. The other fields in the Device section (Notes and Disable Device) can be left as is. If your host template exists in the drop-down, be sure to select the template. Since we are starting with an SNMP-enabled device, if you are not sure which template to select, you can select the Generic SNMP-enabled host template. It is important to know that adding a template to a device will not lock down the device to any specific configuration, as graph templates and queries can be added and removed from a device at anytime. The following screenshot shows how the Add a device form looks. If you look closely at the drop-down, there are very few templates. But you can add device-specific templates as required. The following web site has an excellent collection of Cacti scripts and templates. This web site is aimed at providing tips and tricks to Debian users from novice to expert. The owner also collects and updates all sorts of scripts and templates from the Cacti forum for easy access: http://www.debianhelp.co.uk/cactitemplates.htm Device fields definition Every device that we add has different attributes and values. The following table will clarify the attributes. It is wise to understand all the fields before adding a device in Cacti. Fields Descriptions Description Giving host a meaningful name. This name will be shown in the first column of the device view panel. Hostname Fully qualified hostname or IP. If a fully qualified hostname is being used such as linuxbox1.example.com, Dynamic Name Services (DNS) will be used to resolve the hostname. Host Template Host template is responsible for the types of data that need to be gathered from a specific type of host. Notes Adding notes for the host, anything that is specific to the host. Disable Host Check this box to disable all the checks for this device. This means no polling for this device. Downed Device Detection NONE: Disable downed device detection. Ping and SNMP: Perform both tests. SNMP: Perform SNMP check. Ping: Use ping method. Ping Method ICMP Ping: Perform ICMP test. ICMP on Linux/Unix require root privileges. TCP Ping: Perform a TCP test. UDP Ping: Perform UDP test. Ping Port This option is available for only TCP and UDP Ping. Define the port number here and make sure the firewall is not blocking that port. Ping Timeout Value This value is measured in milliseconds. After the defined time, the test will fail. Ping Retry Count Defines how many times Cacti will ping a host before failing. SNMP Version Version 1: Supported by most of the SNMP-enabled devices. One thing you need to remember is that it doesn't support a 64-bit counter. Version 2: This is also known as SNMPv2c. Supported by most of the SNMP-enabled devices. Version 3: Version 3 supports authentication and encryption.
Read more
  • 0
  • 0
  • 4719
article-image-liferay-its-installation-and-setup
Packt
15 Apr 2013
7 min read
Save for later

Liferay, its Installation and setup

Packt
15 Apr 2013
7 min read
(For more resources related to this topic, see here.) Overview about portals Well, to understand more about what portals are, let me throw some familiar words at you. Have you used, heard, or seen iGoogle, the Yahoo! home page, or MSN? If the answer is yes, then you have been using portals already. All these websites have two things in common. A common dashboard Information from various sources shown on a single page, giving a uniform experience For example, on iGoogle, you can have a gadget showing the weather in Chicago, another gadget to play your favorite game of Sudoku, and a third one to read news from around the globe, everything on the same page without you knowing that all of these are served from different websites! That is what a portal is all about. So, a portal (or web portal) can be thought of as a website that shows, presents, displays, or brings together information or data from various sources and gives the user a uniform browsing experience. The small chunks of information that form the web page are given different names such as gadgets or widgets, portlets or dashlets. Introduction to Liferay Now that you have some basic idea about what portals are, let us revisit the initial statement I made about Liferay. Liferay is an open source portal solution. If you want to create a portal, you can use Liferay to do this. It is written in Java. It is an open source solution, which means the source code is freely available to everyone and people can modify and distribute it. With Liferay you can create basic intranet sites with minimal tweaking. You can also go for a full-fledged enterprise banking portal website with programming, and heavy customizations and integrations. Besides the powerful portal capabilities, Liferay also provides the following: Awesome enterprise and web content management capabilities Robust document management which supports protocols such as CMIS and WebDAV Good social collaboration features Liferay is backed up by a solid and active community, whose members are ever eager to help. Sounds good? So what are we waiting for? Let's take a look at Liferay and its features. Installation and setup In four easy steps, you can install Liferay and run it on your system. Step 1 – Prerequisites Before we go and start our Liferay download, we need to check if we have the requirements for the installation. They are as follows: Memory: 2 GB (minimum), 4 GB (recommended). Disk space: Around 5 GB of free space should be more than enough for the exercises mentioned in the book. The exercises performed in this book are done on Windows XP. So you can use the same or any subsequent versions of Windows OS. Although Liferay can be run on Mac OSX and Linux, it is beyond the scope of this book how to set up Liferay on them. The MySQL database should be installed. As with the OS, Liferay can be run on most of the major databases out there in the market. Liferay is shipped with the Hypersonic database by default for demo purpose, which should not be used for a production environment. Unzip tools such as gzip or 7-Zip. Step 2 – Downloading Liferay You can download the latest stable version of Liferay from https://www.liferay.com/downloads/liferay-portal/available-releases. Liferay comes in the following two versions: Enterprise Edition: This version is not free and you would have to purchase it. This version has undergone rigorous testing cycles to make sure that all the features are bug free, providing the necessary support and patches. Community Edition: This is a free downloadable version that has all the features but no enterprise support provided. Liferay is supported by a lot of open source application servers and the folks at Liferay have made it easy for end users by packaging everything as a bundle. What this means is that if you are asked to have Liferay installed in a JBoss application server, you can just go to the URL previously mentioned and select the Liferay-JBoss bundle to download, which gives you the JBoss Application server installed with Liferay. We will download the Community Edition of the Liferay-Tomcat bundle, which has Liferay preinstalled in the Tomcat server. The stable version at the time of writing this book was Liferay 6.1 GA2. As shown in the following screenshot, just click on Download after making sure that you have selected Liferay bundled with Tomcat and save the ZIP file at an appropriate location: Step 3 – Starting the server After you have downloaded the bundle, extract it to the location of your choice on your machine. You can see a folder named liferay-portal-6.1.1-ce-ga2. The latter part of the name can change based on the version that you download. Let us take a moment to have a look at the folder structure as shown in the following screenshot: The liferay-portal-6.1.1-ce-ga2 folder is what we will refer to as LIFERAY_HOME. This folder contains the server, which in our case is tomcat-7.0.27. Let's refer to this folder as SERVER_HOME. Liferay is created using Java, so to run Liferay we need Java Runtime Environment (JRE). The Liferay bundle is shipped with a JRE by default (as you can see inside our SERVER_HOME). So if you are running a Windows OS, you can directly start and run Liferay. If you are using any other OS, you need to set the JAVA_HOME environment variable. Navigate to SERVER_HOME/webapps. This is where all the web applications are deployed. Delete everything in this folder except marketplace-portlet and ROOT. Now go to SERVER/bin and double-click on startup.bat, since we are using Windows OS. This will bring up a console showing the server startup. Wait till you see the Server Startup message in the console, after which you can access Liferay from the browser. Step 4 – Doing necessary first-time configurations Once the server is up, open your favorite browser and type in http://localhost:8080. You will be shown a screen that performs basic configurations, such as changing the database and name of your portal, deciding what should be the admin name and e-mail address, or changing the default locale. This is a new feature introduced in Liferay 6.1 to ease the first-time setup, which on previous versions had to be done using the property file. Go change the name of the portal, administrator username, and e-mail address. Keep the locale as it is. As I stated earlier, Liferay is shipped with a default Hypersonic database which is normally used for demo purposes. You can change it to MySQL if you want, by selecting the database type from the drop-down list presented, and typing in the necessary JDBC details. I have created a database in MySQL by the name Portal Starter; hence my JDBC URL would contain that. You can create a blank database in MySQL and accordingly change the JDBC URL. Once you are done making your changes, click on the Finish Configuration button as shown in the following screenshot: This will open up a screen, which will show the path where this configuration is saved. What Liferay does behind the scenes is creates a property file named portal-setup-wizard.properties and put all the configurations in that. This, as I said earlier, was created manually in the previous versions of Liferay. Clicking on the Go to my portal button on this screen will take the user to the Terms of Use page. Agree to the terms and proceed further. A screen will be shown to change the password for your admin user that you earlier specified in the Basic Configuration screen. After you change the password, you will be presented with a screen to select a password reminder question. Select a question or create your own question from the drop-down list, set the password reminder, and move on. And that's it!! Finally, you can see the home page of Liferay. That's it and you are done setting up your very first Liferay instance. Summary So, we just gained a quick understanding about portals and Liferay and its installation and setup that teaches you how to set up Liferay on your local machine. Resources for Article : Further resources on this subject: Vaadin Portlets in Liferay User Interface Development [Article] Setting up and Configuring a Liferay Portal [Article] User Interface in Production [Article]
Read more
  • 0
  • 0
  • 4718

article-image-oracle-goldengate-advanced-administration-tasks-i
Packt
20 Sep 2013
19 min read
Save for later

Oracle GoldenGate- Advanced Administration Tasks - I

Packt
20 Sep 2013
19 min read
(For more resources related to this topic, see here.) Upgrading Oracle GoldenGate binaries In this recipe you will learn how to upgrade GoldenGate binaries. You will also learn about GoldenGate patches and how to apply them. Getting ready For this recipe, we will upgrade the GoldenGate binaries from version 11.2.1.0.1 to 11.2.1.0.3 on the source system, that is prim1-ol6-112 in our case. Both of these binaries are available from the Oracle Edelivery website under the part number V32400-01 and V34339-01 respectively. 11.2.1.0.1 binaries are installed under /u01/app/ggate/112101. How to do it... The steps to upgrade the Oracle GoldenGate binaries are: Make a new directory for 11.2.1.0.3 binaries: mkdir /u01/app/ggate/112103 Copy the binaries ZIP file to the server in the new directory. Unzip the binaries file: [ggate@prim1-ol6-112 112103]$ cd /u01/app/ggate/112103 [ggate@prim1-ol6-112 112103]$ unzip V34339-01.zip Archive: V34339-01.zip inflating: fbo_ggs_Linux_x64_ora11g_64bit.tar inflating: Oracle_GoldenGate_11.2.1.0.3_README.doc inflating: Oracle GoldenGate_11.2.1.0.3_README.txt inflating: OGG_WinUnix_Rel_Notes_11.2.1.0.3.pdf Install the new binaries in /u01/app/ggate/112103: [ggate@prim1-ol6-112 112103]$ tar -pxvf fbo_ggs_Linux_x64_ora11g_64bit.tar Stop the processes in the existing installation: [ggate@prim1-ol6-112 112103]$ cd /u01/app/ggate/112101 [ggate@prim1-ol6-112 112101]$ ./ggsci Oracle GoldenGate Command Interpreter for Oracle Version 11.2.1.0.1 OGGCORE_11.2.1.0.1_PLATFORMS_120423.0230_FBO Linux, x64, 64bit (optimized), Oracle 11g on Apr 23 2012 08:32:14 Copyright (C) 1995, 2012, Oracle and/or its affiliates. All rights reserved. GGSCI (prim1-ol6-112.localdomain) 1> stop * Sending STOP request to EXTRACT EGGTEST1 ... Request processed. Sending STOP request to EXTRACT PGGTEST1 ... Request processed. Stop the manager process: GGSCI (prim1-ol6-112.localdomain) 2> STOP MGRManager process is required by other GGS processes.Are you sure you want to stop it (y/n)? ySending STOP request to MANAGER ...Request processed.Manager stopped. Copy the subdirectories to the new binaries: [ggate@prim1-ol6-112 112101]$ cp -R dirprm /u01/app/ggate/112103/[ggate@prim1-ol6-112 112101]$ cp -R dirrpt /u01/app/ggate/112103/[ggate@prim1-ol6-112 112101]$ cp -R dirchk /u01/app/ggate/112103/[ggate@prim1-ol6-112 112101]$ cp -R BR /u01/app/ggate/112103/[ggate@prim1-ol6-112 112101]$ cp -R dirpcs /u01/app/ggate/112103/ [ggate@prim1-ol6-112 112101]$ cp -R dirdef /u01/app/ggate/112103/[ggate@prim1-ol6-112 112101]$ cp -R dirout /u01/app/ggate/112103/[ggate@prim1-ol6-112 112101]$ cp -R dirdat /u01/app/ggate/112103/[ggate@prim1-ol6-112 112101]$ cp -R dirtmp /u01/app/ggate/112103/ Modify any parameter files under dirprm if you have hardcoded old binaries path in them. Edit the ggate user profile and update the value of the GoldenGate binaries home: vi .profile export GG_HOME=/u01/app/ggate/112103 Start the manager process from the new binaries: [ggate@prim1-ol6-112 ~]$ cd /u01/app/ggate/112103/ [ggate@prim1-ol6-112 112103]$ ./ggsci Oracle GoldenGate Command Interpreter for Oracle Version 11.2.1.0.3 14400833 OGGCORE_11.2.1.0.3_PLATFORMS_120823.1258_FBO Linux, x64, 64bit (optimized), Oracle 11g on Aug 23 2012 20:20:21 Copyright (C) 1995, 2012, Oracle and/or its affiliates. All rights reserved. GGSCI (prim1-ol6-112.localdomain) 1> START MGR Manager started. Start the processes: GGSCI (prim1-ol6-112.localdomain) 18> START EXTRACT * Sending START request to MANAGER ... EXTRACT EGGTEST1 starting Sending START request to MANAGER ... EXTRACT PGGTEST1 starting How it works... The method to upgrade the GoldenGate binaries is quite straightforward. As seen in the preceding section, you need to download and install the binaries on the server in a new directory. After this, you would stop the all GoldenGate processes that are running from the existing binaries. Then you would copy all the important GoldenGate directories with parameter files, trail files, report files, checkpoint files, and recovery files to the new binaries. If your trail files are kept on a separate filesystem which is linked to the dirdat directory using a softlink, then you would just need to create a new softlink under the new GoldenGate binaries home. Once all the files are copied, you would need to modify the parameter files if you have the path of the existing binaries hardcoded in them. The same would also need to be done in the OS profile of the ggate user. After this, you just start the manager process and rest of the processes from the new home. GoldenGate patches are all delivered as full binaries sets. This makes the procedure to patch the binaries exactly the same as performing major release upgrades. Table structure changes in GoldenGate environments with similar table definitions Almost all of the applications systems in IT undergo some change over a period of time. This change might include a fix of an identified bug, an enhancement or some configuration change required due to change in any other part of the system. The data that you would replicate using GoldenGate will most likely be part of some application schema. These schemas, just like the application software, sometimes require some changes which are driven by the application vendor. If you are replicating DDL along with DML in your environment then these schema changes will most likely be replicated by GoldenGate itself. However, if you are only replicating only DML and there are any DDL changes in the schema particularly around the tables that you are replicating, then these will affect the replication and might even break it. In this recipe, you will learn how to update the GoldenGate configuration to accommodate the schema changes that are done to the source system. This recipe assumes that the definitions of the tables that are replicated are similar in both the source and target databases. Getting ready For this recipe we are making the following assumptions: GoldenGate is set up to replicate only DML changes between the source and target environments. The application will be stopped for making schema changes in the source environment. The table structures in the source and target database are similar. The replication is configured for all objects owned by a SCOTT user using a SCOTT.* clause. The GoldenGate Admin user has been granted SELECT ANY TABLE in the source database and INSERT ANY TABLE, DELETE ANY TABLE, UPDATE ANY TABLE, SELECT ANY TABLE in the target database. The schema changes performed in this recipe are as follows: Add a new column called DOB (DATE) to the EMP table. Modify the DNAME column in the DEPT table to VARCHAR(20). Add a new table called ITEMS to the SCOTT schema: ITEMS ITEMNO NUMBER(5) PRIMARY KEY NAME VARCHAR(20) Add a new table called SALES to the SCOTT schema: SALES INVOICENO NUMBER(9) PRIMARY KEY ITEMNO NUMBER(5) FOREIGN KEY ITEMS(ITEMNO) EMPNO NUMBER(4) FOREIGN KEY EMP(EMPNO) Load the values for the DOB column in the EMP table. Load a few records in the ITEMS table. How to do it… Here are the steps that you can follow to implement the preceding schema changes in the source environment: Ensure that the application accessing the source database is stopped. There should not be any process modifying the data in the database. Once you have stopped the application, wait for 2 to 3 minutes so that all pending redo is processed by the GoldenGate extract. Check the latest timestamp read by the Extract and Datapump processes and ensure it is the current timestamp: GGSCI (prim1-ol6-112.localdomain) 9> INFO EXTRACT EGGTEST1 GGSCI (prim1-ol6-112.localdomain) 10> INFO EXTRACT * EXTRACT EGGTEST1 Last Started 2013-03-25 22:24 Status RUNNING Checkpoint Lag 00:00:00 (updated 00:00:07 ago) Log Read Checkpoint Oracle Redo Logs 2013-03-25 22:35:06 Seqno 350, RBA 11778560 SCN 0.11806849 (11806849) EXTRACT PGGTEST1 Last Started 2013-03-25 22:24 Status RUNNING Checkpoint Lag 00:00:00 (updated 00:00:04 ago) Log Read Checkpoint File /u01/app/ggate/dirdat/st000010 2013-03-25 22:35:05.000000 RBA 7631 Stop the Extract and Datapump processes in the source environment: GGSCI (prim1-ol6-112.localdomain) 1> STOP EXTRACT * Sending STOP request to EXTRACT EGGTEST1 ... Request processed. Sending STOP request to EXTRACT PGGTEST1 ... Request processed. Check the status of the Replicat process in the target environment and ensure that it has processed the timestamp noted in step 3: GGSCI (stdby1-ol6-112.localdomain) 54> INFO REPLICAT * REPLICAT RGGTEST1 Last Started 2013-03-25 22:25 Status RUNNING Checkpoint Lag 00:00:00 (updated 00:00:04 ago) Log Read Checkpoint File ./dirdat/rt000061 2013-03-25 22:37:04.950188 RBA 10039 Stop the Replicat process in the target environment: GGSCI (stdby1-ol6-112.localdomain) 48> STOP REPLICAT * Sending STOP request to REPLICAT RGGTEST1 ... Request processed. Apply the schema changes to the source database: SQL> ALTER TABLE SCOTT.EMP ADD DOB DATE; Table altered. SQL> ALTER TABLE SCOTT.DEPT MODIFY DNAME VARCHAR(20); Table altered. SQL> CREATE TABLE SCOTT.ITEMS ( ITEMNO NUMBER(5) PRIMARY KEY, NAME VARCHAR(20)); Table created. SQL> CREATE TABLE SCOTT.SALES ( INVOICENO NUMBER(9) PRIMARY KEY, ITEMNO NUMBER(5) REFERENCES SCOTT.ITEMS(ITEMNO), EMPNO NUMBER(4) REFERENCES SCOTT.EMP(EMPNO)); Table created. SQL> UPDATE SCOTT.EMP SET DOB=TO_DATE('01-01-1980','DD-MM-YYYY'); 14 rows updated. SQL> INSERT INTO SCOTT.ITEMS VALUES (1,'IRON'); 1 row created. SQL> INSERT INTO SCOTT.ITEMS VALUES (2,'COPPER'); 1 row created. SQL> INSERT INTO SCOTT.ITEMS VALUES (3,'GOLD'); 1 row created. SQL> INSERT INTO SCOTT.ITEMS VALUES (4,'SILVER'); 1 row created. SQL> COMMIT; Commit complete. Apply the schema changes to the target database: SQL> ALTER TABLE SCOTT.EMP ADD DOB DATE; Table altered. SQL> ALTER TABLE SCOTT.DEPT MODIFY DNAME VARCHAR(20); Table altered. SQL> CREATE TABLE SCOTT.ITEMS ( ITEMNO NUMBER(5) PRIMARY KEY, NAME VARCHAR(20)); Table created. SQL> CREATE TABLE SCOTT.SALES ( INVOICENO NUMBER(9) PRIMARY KEY, ITEMNO NUMBER(5) REFERENCES SCOTT.ITEMS(ITEMNO), EMPNO NUMBER(4) REFERENCES SCOTT.EMP(EMPNO)); Table created. SQL> UPDATE SCOTT.EMP SET DOB=TO_DATE('01-01-1980','DD-MM-YYYY'); 14 rows updated. SQL> INSERT INTO SCOTT.ITEMS VALUES (1,'IRON'); 1 row created. SQL> INSERT INTO SCOTT.ITEMS VALUES (2,'COPPER'); 1 row created. SQL> INSERT INTO SCOTT.ITEMS VALUES (3,'GOLD'); 1 row created. SQL> INSERT INTO SCOTT.ITEMS VALUES (4,'SILVER'); 1 row created. SQL> COMMIT; Commit complete. Add supplemental logging for the newly added tables: GGSCI (prim1-ol6-112.localdomain) 4> DBLOGIN USERID GGATE_ADMIN@ DBORATEST Password: Successfully logged into database. GGSCI (prim1-ol6-112.localdomain) 5> ADD TRANDATA SCOTT.ITEMS Logging of supplemental redo data enabled for table SCOTT.ITEMS. GGSCI (prim1-ol6-112.localdomain) 6> ADD TRANDATA SCOTT.SALES Logging of supplemental redo data enabled for table SCOTT.SALES. Alter the Extract and Datapump processes to skip the changes generated by the Application Schema Patch: GGSCI (prim1-ol6-112.localdomain) 7> ALTER EXTRACT EGGTEST1 BEGIN NOW EXTRACT altered. GGSCI (prim1-ol6-112.localdomain) 8> ALTER EXTRACT PGGTEST1 BEGIN NOW EXTRACT altered. Start the Extract and Datapump in the source environment: GGSCI (prim1-ol6-112.localdomain) 9> START EXTRACT * Sending START request to MANAGER ... EXTRACT EGGTEST1 starting Sending START request to MANAGER ... EXTRACT PGGTEST1 starting Start the Replicat process in the target environment: GGSCI (stdby1-ol6-112.localdomain) 56> START REPLICAT RGGTEST1 Sending START request to MANAGER ... REPLICAT RGGTEST1 starting How it works... The preceding steps cover a high level procedure that you can follow to modify the structure of the replicated tables in your GoldenGate configuration. Before you start to alter any processes or parameter file, you need to ensure that the applications are stopped and no user sessions in the database are modifying the data in the tables that you are replicating. Once the application is stopped, we check that all the redo data has been processed by GoldenGate processes and then stop. At this point we run the scripts that need to be run to make DDL changes to the database. This step needs to be run on both the source and target database as we will not be replicating these changes using GoldenGate. Once this is done, we alter the GoldenGate processes to start from the current time and start them. There's more... Some of the assumptions made in the earlier procedure might not hold true for all environments. Let's see what needs to be done in such cases where the environment does not satisfy these conditions: Specific tables defined in GoldenGate parameter files Unlike the earlier example, where the tables are defined in the parameter files using a schema qualifier for example SCOTT.*, if you have individual tables defined in the GoldenGateparameterfiles, you would need to modify the GoldenGate parameter files to add these newly created tables to include them in replication. Individual table permissions granted to the GoldenGate Admin user If you have granted table-specific permissions to the GoldenGate Admin user in the source and target environments, you would need to grant them on the newly added tables to allow the GoldenGate user to read their data in the source environment and also to apply the changes to these tables in the target environment. Supplemental logging for modified tables without any keys If you are adding or deleting any columns from the tables in the source database which do not have any primary/unique keys, you would then need to drop the existing supplemental log group and read them. This is because when there are no primary/unique keys in a table, GoldenGate adds all columns to the supplemental log group. This supplemental log group will have to be modified when the structure of the underlying table is modified. Supplemental log groups with all columns for modified tables In some cases, you would need to enable supplemental logging on all columns of the source tables that you are replicating. This is mostly applicable for consolidation replication topologies where all changes are captured and converted into INSERTs in the target environment, which usually is a Data warehouse. In such cases, you need to drop and read the supplemental logging on the tables in which you are adding or removing any columns. Table structure changes in GoldenGate environments with different table definitions In this recipe you will learn how to perform table structure changes in a replication environment where the table structures in the source and target environments are not similar. Getting ready For this recipe we are making the following assumptions: GoldenGate is set up to replicate only DML changes between the source and target environments. The application will be stopped for making schema changes in the source environment. The table structures in the source and target databases are not similar. The GoldenGate Admin user has been granted SELECT ANY TABLE in the source database and INSERT ANY TABLE, DELETE ANY TABLE, UPDATE ANY TABLE, SELECT ANY TABLE in the target database. The definition file was generated for the source schema and is configured in the replicat parameter file. The schema changes performed in this recipe are as follows: Add a new column called DOB (DATE) to the EMP table. Modify the DNAME column in the DEPT table to VARCHAR(20). Add a new table called ITEMS to the SCOTT schema: ITEMS ITEMNO NUMBER(5) PRIMARY KEY NAME VARCHAR(20) Add a new table called SALES to the SCOTT schema: SALES INVOICENO NUMBER(9) PRIMARY KEY ITEMNO NUMBER(5) FOREIGN KEY ITEMS(ITEMNO) EMPNO NUMBER(4) FOREIGN KEY EMP(EMPNO) Load the values for the DOB column in the EMP table. Load a few records in the ITEMS table. How to do it... Here are the steps that you can follow to implement the previous schema changes in the source environment: Ensure that the application accessing the source database is stopped. There should not be any process modifying the data in the database. Once you have stopped the application, wait for 2 to 3 minutes so that all pending redo is processed by the GoldenGate extract. Check the latest timestamp read by the Extract and Datapump process, and ensure it is the current timestamp: GGSCI (prim1-ol6-112.localdomain) 9> INFO EXTRACT EGGTEST1 GGSCI (prim1-ol6-112.localdomain) 10> INFO EXTRACT * EXTRACT EGGTEST1 Last Started 2013-03-28 10:12 Status RUNNING Checkpoint Lag 00:00:00 (updated 00:00:07 ago) Log Read Checkpoint Oracle Redo Logs 2013-03-28 10:16:06 Seqno 352, RBA 12574320 SCN 0.11973456 (11973456) EXTRACT PGGTEST1 Last Started 2013-03-28 10:12 Status RUNNING Checkpoint Lag 00:00:00 (updated 00:00:04 ago) Log Read Checkpoint File /u01/app/ggate/dirdat/st000010 2013-03-28 10:15:43.000000 RBA 8450 Stop the Extract and Datapump processes in the source environment: GGSCI (prim1-ol6-112.localdomain) 1> STOP EXTRACT * Sending STOP request to EXTRACT EGGTEST1 ... Request processed. Sending STOP request to EXTRACT PGGTEST1 ... Request processed. Check the status of the Replicat process in the target environment and ensure that it has processed the timestamp noted in step 3: GGSCI (stdby1-ol6-112.localdomain) 54> INFO REPLICAT * REPLICAT RGGTEST1 Last Started 2013-03-28 10:15 Status RUNNING Checkpoint Lag 00:00:00 (updated 00:00:04 ago) Log Read Checkpoint File ./dirdat/rt000062 2013-03-28 10:15:04.950188 RBA 10039 Stop the Replicat process in the target environment: GGSCI (stdby1-ol6-112.localdomain) 48> STOP REPLICAT * Sending STOP request to REPLICAT RGGTEST1 ... Request processed. Apply the schema changes to the source database: SQL> ALTER TABLE SCOTT.EMP ADD DOB DATE; Table altered. SQL> ALTER TABLE SCOTT.DEPT MODIFY DNAME VARCHAR(20); Table altered. SQL> CREATE TABLE SCOTT.ITEMS ( ITEMNO NUMBER(5) PRIMARY KEY, NAME VARCHAR(20)); Table created. SQL> CREATE TABLE SCOTT.SALES ( INVOICENO NUMBER(9) PRIMARY KEY, ITEMNO NUMBER(5) REFERENCES SCOTT.ITEMS(ITEMNO), EMPNO NUMBER(4) REFERENCES SCOTT.EMP(EMPNO)); Table created. SQL> UPDATE SCOTT.EMP SET DOB=TO_DATE('01-01-1980','DD-MM-YYYY'); 14 rows updated. SQL> INSERT INTO SCOTT.ITEMS VALUES (1,'IRON'); 1 row created. SQL> INSERT INTO SCOTT.ITEMS VALUES (2,'COPPER'); 1 row created. SQL> INSERT INTO SCOTT.ITEMS VALUES (3,'GOLD'); 1 row created. SQL> INSERT INTO SCOTT.ITEMS VALUES (4,'SILVER'); 1 row created. SQL> COMMIT; Commit complete. Apply the schema changes to the target database: SQL> ALTER TABLE SCOTT.EMP ADD DOB DATE; Table altered. SQL> ALTER TABLE SCOTT.DEPT MODIFY DNAME VARCHAR(20); Table altered. SQL> CREATE TABLE SCOTT.ITEMS ( ITEMNO NUMBER(5) PRIMARY KEY, NAME VARCHAR(20)); Table created. SQL> CREATE TABLE SCOTT.SALES ( INVOICENO NUMBER(9) PRIMARY KEY, ITEMNO NUMBER(5) REFERENCES SCOTT.ITEMS(ITEMNO), EMPNO NUMBER(4) REFERENCES SCOTT.EMP(EMPNO)); Table created. SQL> UPDATE SCOTT.EMP SET DOB=TO_DATE('01-01-1980','DD-MM-YYYY'); 14 rows updated. SQL> INSERT INTO SCOTT.ITEMS VALUES (1,'IRON'); 1 row created. SQL> INSERT INTO SCOTT.ITEMS VALUES (2,'COPPER'); 1 row created. SQL> INSERT INTO SCOTT.ITEMS VALUES (3,'GOLD'); 1 row created. SQL> INSERT INTO SCOTT.ITEMS VALUES (4,'SILVER'); 1 row created. SQL> COMMIT; Commit complete. Add supplemental logging for the newly added tables: GGSCI (prim1-ol6-112.localdomain) 4> DBLOGIN USERID GGATE_ADMIN@DBORATEST Password: Successfully logged into database. GGSCI (prim1-ol6-112.localdomain) 5> ADD TRANDATA SCOTT.ITEMS Logging of supplemental redo data enabled for table SCOTT.ITEMS. GGSCI (prim1-ol6-112.localdomain) 6> ADD TRANDATA SCOTT.SALES Logging of supplemental redo data enabled for table SCOTT.SALES. Update the parameter file for generating definitions as follows: vi $GG_HOME/dirprm/defs.prm DEFSFILE ./dirdef/defs.def USERID ggate_admin@dboratest, PASSWORD XXXX TABLE SCOTT.EMP; TABLE SCOTT.DEPT; TABLE SCOTT.BONUS; TABLE SCOTT.DUMMY; TABLE SCOTT.SALGRADE; TABLE SCOTT.ITEMS; TABLE SCOTT.SALES; Generate the definitions in the source environment: ./defgen paramfile ./dirprm/defs.prm Push the definitions file to the target server using scp: scp ./dirdef/defs.def stdby1-ol6-112:/u01/app/ggate/dirdef/ Edit the Extract and Datapump process parameter to include the newly created tables if you have specified individual table names in them. Alter the Extract and Datapump processes to skip the changes generated by the Application Schema Patch: GGSCI (prim1-ol6-112.localdomain) 7> ALTER EXTRACT EGGTEST1 BEGIN NOW EXTRACT altered. GGSCI (prim1-ol6-112.localdomain) 8> ALTER EXTRACT PGGTEST1 BEGIN NOW EXTRACT altered. Start the Extract and Datapump in the source environment: GGSCI (prim1-ol6-112.localdomain) 9> START EXTRACT * Sending START request to MANAGER ... EXTRACT EGGTEST1 starting Sending START request to MANAGER ... EXTRACT PGGTEST1 starting Edit the Replicat process parameter file to include the tables: ./ggsci EDIT PARAMS RGGTEST1 REPLICAT RGGTEST1 USERID GGATE_ADMIN@TGORTEST, PASSWORD GGATE_ADMIN DISCARDFILE /u01/app/ggate/dirrpt/RGGTEST1.dsc,append,MEGABYTES 500 SOURCEDEFS ./dirdef/defs.def MAP SCOTT.BONUS, TARGET SCOTT.BONUS; MAP SCOTT.SALGRADE, TARGET SCOTT.SALGRADE; MAP SCOTT.DEPT, TARGET SCOTT.DEPT; MAP SCOTT.DUMMY, TARGET SCOTT.DUMMY; MAP SCOTT.EMP, TARGET SCOTT.EMP; MAP SCOTT.EMP,TARGET SCOTT.EMP_DIFFCOL_ORDER; MAP SCOTT.EMP, TARGET SCOTT.EMP_EXTRACOL, COLMAP(USEDEFAULTS, LAST_UPDATE_TIME = @DATENOW ()); MAP SCOTT.SALES, TARGET SCOTT.SALES; MAP SCOTT.ITEMS, TARGET SCOTT.ITEMS; Start the Replicat process in the target environment: GGSCI (stdby1-ol6-112.localdomain) 56> START REPLICAT RGGTEST1 Sending START request to MANAGER ... REPLICAT RGGTEST1 starting How it works... You can follow the previously mentioned procedure to apply any DDL changes to the tables in the source database. This procedure is valid for environments where existing table structures between the source and the target databases are not similar. The key things to note in this method are: The changes should only be made when all the changes extracted by GoldenGate are applied to the target database, and the replication processes are stopped. Once the DDL changes have been performed in the source database, the definitions file needs to be regenerated. The changes that you are making to the table structures needs to be performed on both sides. There's more… Some of the assumptions made in the earlier procedure might not hold true for all environments. Let's see what needs to be done in cases where the environment does not satisfy these conditions: Individual table permissions granted to the GoldenGate Admin user If you have granted table-specific permissions to the GoldenGate Admin user in the source and target environments, you would need to grant them on the newly added tables to allow the GoldenGate user to read their data in the source environment and also to apply the changes to these tables in the target environment. Supplemental logging for modified tables without any keys If you are adding or deleting any columns from the tables in the source database which do not have any primary/unique keys, you would then need to drop the existing supplemental log group and read them. This is because when there are no primary/unique keys in a table, GoldenGate adds all columns to the supplemental log group. This supplemental log group will need to be modified when the structure of the underlying table is modified. Supplemental log groups with all columns for modified tables In some cases, you would need to enable supplemental logging on all columns of the source tables that you are replicating. This is mostly applicable for consolidation replication topologies where all changes are captured and converted into INSERTs in the target environment, which usually is a Data warehouse. In such cases, you need to drop and read the supplemental logging on the tables in which you are adding or removing any columns.
Read more
  • 0
  • 0
  • 4717

article-image-getting-store
Packt
28 Oct 2013
21 min read
Save for later

Getting into the Store

Packt
28 Oct 2013
21 min read
(For more resources related to this topic, see here.) This all starts by visiting https://appdev.microsoft.com/StorePortals, which will get you to the store dashboard that you use to submit and manage your applications. If you already have an account you'll just log in here and proceed. If not, we'll take a look at ways of getting it set up. There are a couple of ways to get a store account, which you will need before you can submit any game or application to the store. There are also two different types of accounts: Individual accounts Company accounts In most cases you will only need the first option. It's cheaper and easier to get, and you won't require the enterprise features provided by the company account for a game. For this reason we'll focus on the individual account. To register you'll need a credit card for verification, even if you gain a free account another way. Just follow the registration instructions, pay the fee, and complete verification, after which you'll be ready to go. Free accounts Students and developers with MSDN subscriptions can access registration codes that waive the fee for a minimum of one year. If you meet either of these requirements you can gain a code using the respective methods, and use that code during the registration process to set the fee to zero. Students can access their free accounts using the DreamSpark service that Microsoft runs. To access this you need to create an account on www.dreamspark.com and create an account. From there follow the steps to verify your student status and visit https://www.dreamspark.com/Student/Windows-Store-Access.aspx to get your registration code. If you have access to an MSDN subscription you can use this to gain a store account for free. Just log in to your account and in your account benefits overview you should be able to generate your registration code. Submitting your game So your game is polished and ready to go. What do you need to do to get it in the store? First log in to the dashboard and select Submit an App from the menu on the left. Here you can see the steps required to submit the app. This may look like a lot to do, but don't worry. Most of these are very simple to resolve and can be done before you even start working on the game. The first step is to choose a name for your game, and this can be done whenever you want. By reserving a name and creating the application entry you have a year to submit your application, giving you plenty of time to complete it. This is why it's a good idea to jump in and register your application once you have a name for it. If you change your mind later and want a different name you can always change it. The next step is to choose how and where you will sell your game. The other thing you need to choose here are the markets you want to sell your game in. This can be an area you need to be careful of, because the markets you choose here define the localization or content you need to watch for in your game. Certain markets are restrictive and including content that isn't appropriate for a market you say you want to sell in can cause you to fail the certification process. Once that is done you need to choose when you want to release your game—you can choose to release as soon as certification finishes or on a specific date, and then you choose the app category, which in this case will be Games. Don't forget to specify the genre of your game as the sub-category so players can find it. The final option on the Selling Details page which applies to us is the Hardware requirements section. Here we define the DirectX feature-level required for the game, and the minimum RAM required to run it. This is important because the store can help ensure that players don't try to play your game on systems that cannot run it. The next section allows you to define the in-app offers that will be made available to players. The Age rating and rating certificates section allows you to define the minimum age required to play the game, as well as submit official ratings certificates from ratings boards so that they may be displayed in the store to meet legal requirements. The latter part is optional in some cases, and may affect where you can submit your game depending on local laws. Aside from official ratings, all applications and games submitted to the store require a voluntary rating, chosen from one of the following age options: 3+ 7+ 12+ 16+ 18+ While all content is checked, the 7+ and 3+ ratings both have extra checks because of the extra requirements for those age ranges. The 3+ rating is especially restrictive as apps submitted with that age limit may not contain features that could connect to online services, collect personal information, or use the webcam or microphone. To play it safe it's recommended the 12+ rating is chosen, and if you're still uncertain, higher is safer. GDF Certificates The other entry required here if you have official ratings certificates is a GDF file. This is a Game Definition File, which defines the different ratings in a single location and provides the necessary information to display the rating and inform any parental settings. To do this you need to use the GDFMAKER.exe utility that ships with the Windows 8 SDK, and generate a GDF file which you can submit to the store. Alongside that you need to create a DLL containing that file (as a resource) without any entry point to include in the application package. For full details on how to create the GDF as well as the DLL, view the following MSDN article: http://msdn.microsoft.com/en-us/library/windows/apps/hh465153.aspx The final section before you need to submit your compiled application package is the cryptography declaration. For most games you should be able to declare that you aren't using any cryptography within the game and quickly move through this step. If you are using cryptography, including encrypting game saves or data files, you will need to declare that here and follow the instructions to either complete the step or provide an Export Control Classification Number (ECCN). Now you need to upload the compiled app package before you can continue, so we'll take a look at what it takes to do that before you continue. App packages To submit your game to the store, you need to package it up in a format that makes it easy to upload, and easy for the store to distribute. This is done by compiling the application as an .appx file. But before that happens we need to ensure we have defined all of the required metadata, and fulfill the certification requirements, otherwise we'll be uploading a package only to fail soon after. Part of this is done through the application manifest editor, which is accessible in Visual Studio by double-clicking on the Package.appxmanifest file in solution explorer. This editor is where you specify the name that will be seen in the start menu, as well as the icons used by the application. To pass certification all icons have to be provided at 100 percent DPI, which is referred to as Scale 100 in the editor. Icon/Image Base resolution Required Standard 150 x 150 px Yes Wide 310 x 150 px If Wide Tile Enabled Small 30 x 30 px Yes Store 50 x 50 px Yes Badge 24 x 24 px If Toasts Enabled Splash 620 x 300 px Yes If you wish to provide a higher quality images for people running on high DPI setups, you can do so with a simple filename change. If you add scale-XXX to your filename, just before the extension, and replace XXX with one of the following values, Windows will automatically make use of it at the appropriate DPI. scale-100 scale-140 scale-180 In the following image you can see the options available for editing the visual assets in the application. These all apply to the start menu and application start-up experience, including the splash screen and toast notifications. Toast Notifications in Windows 8 are pop-up notifications that slide in from the edge of the screen and show the users some information for a short period of time. They can click on the toast to open the application if they want. Alongside Live Tiles, Toast Notifications allow you to give the user information when the application is not running (although they work when the application is running). The previous table shows the different images you required for a Windows 8 application, and if they are mandatory or just required in certain situations. Note that this does not include the imagery required for the store, which includes some screenshots of the application and optional promotional art in case you want your application to be featured. You must replace all of the required icons with your own. Automated checks during certification will detect the use of the default "box" icon shown in the previous screenshot and automatically fail the submission. Capabilities Once you have the visual aspects in place, you need to declare the capabilities that the application will receive. Your game may not need any, however you should still only specify what you need to run, as some of these capabilities come with extra implications and non-obvious requirements. Adding a privacy policy One of those requirements is the privacy policy. Even if you are creating a game, there may be situations where you are collecting private information, which requires you to have a privacy policy. The biggest issue here is connecting to the internet. If your game marks any of the Internet capabilities in the manifest, you automatically trigger a check for a privacy policy as private information—in this case an IP address—is being shared. To avoid failing certification for this, you need to put together a privacy policy if you collect privacy information, or use any of the capabilities that would indicate you collect information. These include the Internet capabilities as well as location, webcam, and microphone capabilities. This privacy policy just needs to describe what you will do with the information, and directly mention your game and publisher name. Once you have the policy written, it needs to be posted in two locations. The first is a publicly accessible website, which you will provide a link to when filling out the description after uploading your game. The second is within the game itself. It is recommended you place this policy in the Windows 8 provided settings menu, which you can build using XAML or your own code. If you're going with a completely native Windows 8 application you may want to display the policy in your own way and link to it from options within your game. Declarations Once you've indicated the capabilities you want, you need to declare any operating system integration you've done. For most games you won't use this, however if you're taking advantage of Windows 8 features such as share targets (the destination for data shared using the Share Charm), or you have a Game Definition File, you will need to declare it here and provide the required information for the operating system. In the case of the GDF, you need to provide the file so that the parental controls system can make use of the ratings to appropriately control access. Certification kit The next step is to make sure you aren't going to fail the automated tests during certification. Microsoft provides the same automated tests used when you submit your app in the Windows Application Certification Kit (WACK). WACK is installed by default with Visual Studio 2012 or higher version. There are two ways to run the test: after you build your application package, or by running the kit directly against an installed app. We'll look at the latter first, as you might want to run the test on your deployed test game well before you build anything for the store. This is also the only way to run the WACK on a WinRT device, if you want to cover all bases. If you haven't already deployed or tested your app, deploy it using the Build menu in Visual Studio and then search for the Windows App Cert Kit using the start menu (just start typing). When you run this you will be given an option to choose which type of application you want to validate. In this case we want to select the Windows Store App option, which will then give you access to the list of apps installed on your machine. From there it's just a matter of selecting the app you want and starting the test. At this point you will want to leave your machine alone until the automated tests are complete. Any interference could lead to an incorrect failure of the certification tests. The results will indicate ways you can fix any issues; however, you should be fine for most of the tests. The biggest issues will arise from third party libraries that haven't been developed or ported to Windows 8. In this case the only option is to fix them yourself (if they're open source) or find an alternative. Once you have the test passing, or you feel confident that it won't be an issue, you need to create app packages that are compatible with the store. At this point your game will be associated with the submission you have created in the Windows Store dashboard so that it is prepared for upload. Creating your app packages To do this, right click on your game project in Visual Studio and click on Create App Packages inside the Store menu. Once you do that, you'll be asked if you want to create a package for the store. The difference between the two options comes down to how the package is signed. If you choose No here, you can create a package with your test certificate, which can be distributed for testing. These packages must be manually installed and cannot be submitted to the store. You can, however, use this type of package on other machines to install your game for testers to try out. Choosing No will give you a folder with a .ps1 file (Powershell), which you can run to execute the install script. Choosing Yes at this option will take you to a login screen where you can enter your Windows Store developer account details. Once you've logged in you will be presented with a list of applications that you have registered with the store. If you haven't yet reserved the name of your application, you can click on the Reserve Name link, which will take you directly to the appropriate page in the store dashboard. Otherwise select the name of the game you're trying to build and click on Next. The next screen will allow you to specify which architectures to build for, and the version number of the built package. As this is a C++ game, we need to provide separate packages for the ARM, x86, and x64 builds, depending on what you want to support. Simply providing an x86 and ARM build will cover the entire market; 64 bit can be nice to have if you need a lot of memory, but ultimately it is optional, and some users may not even be able to run x64 code. When you're ready click on Create and Visual Studio will proceed to build your game and compile the requested packages, placing them in the directory specified. If you've built for the store, you will need the .appxupload files from this directory when you proceed to upload your game. Once the build has completed you will be asked if you want to launch the Windows Application Certification Kit. As mentioned previously this will test your game for certification failures, and if you're submitting to the store it's strongly recommended you run this. Doing so at this screen will automatically deploy the built package and run the test, so ensure you have a little bit of time to let it run. Uploading and submitting Now that you have a built app package you can return to the store dashboard to submit your game. Just edit the submission you made previously and enter the Packages section, which will take you to the page where you can upload the appxupload file. Once you have successfully uploaded your game you will gain access to the next section, the Description. This is where you define the details that will be displayed in the store. This is also where your marketing skills come into play as you prepare the content that will hopefully get players to buy your game. You start with the description of your game, and any big feature bullet points you want to emphasize. This is the best place to mention any reviews or praise, as well as give a quick description that will help the players decide if they want to try your game. You can have a number of app features listed; however, like any "back of the box" bullet points, keep them short and exciting. Along with the description, the store requires at least one screenshot to display to the potential player. These screenshots need to be of the entire screen, and that means they need to be at least 1366x768, which is the minimum resolution of Windows 8. These are also one of the best ways to promote your game, so ensure you take some great screenshots that show off the fun and appeal of your game. There are a few ways to take a screenshot of your game. If you're testing in the simulator you can use the screenshot icon on the right toolbar of the simulator to take the screenshot. If not, you can use Windows Key + Prt Scr SysRq to take a screenshot of your entire screen, and then use that (or edit it if you have multiple monitors). Screenshots taken with either of these tools can be found in the Screenshots folder within your Pictures library. There are two other small pieces of information that are required during this stage: Copyright Info and Support contact info. For the support info, an e-mail address will usually suffice. At this point you can also include your website and, if applicable to your game, a link to the privacy policy included in your game. Note that if you require a privacy policy, it must be included in two places: your game, and the privacy policy field on this form. The last items you may want to add here are promotional images. These images are intended for use in store promotions and allow Microsoft to easily feature your game with larger promotional imagery in prominent locations within the store. If you are serious about maximizing the reach of your game, you will want to include these images. If you don't, the number of places your game can be featured will be reduced. At a minimum the 414x180 px image should be included if you want some form of promotion. Now you're almost done! The next section allows you to leave notes for the testing team. This is where you would leave test account details for any features in your game that require an account so that they can test those features. This is also the location to leave any notes about testing in case there are situations where you can point out any features that might not be obvious. In certain situations you may have an exemption from Microsoft for a certification requirement; this would be where you include that exemption. When every step has been completed and you have tick marks in all of the stages, the Submit for Certification button will unlock, allowing you to complete your submission and send it off for certification. At this stage a number of automated tests will run before human testers will try your game on a variety of devices to ensure it fits the requirements for the store. If all goes well, you will receive an email notifying you of your successful certification and, depending on if you set the release date as ASAP, you will find your game in the store a few hours later (it may take a few hours to appear in the store once you receive an email informing you that your game or app is in the store). Certification tips Your first stop should be the certification requirements page, which lists all of the current requirements your game will be tested for: http://msdn.microsoft.com/en-us/library/windows/apps/hh694083.aspx. There are some requirements that you should take note of, and in this section we'll take a look at ways to help ensure you pass those requirements. Privacy The first of course is the privacy policy. As mentioned before, if your game collects any sort of personal information, you will need that policy in two places: In full text within the game Accessible through an Internet link The default app template generated by Visual Studio automatically enables the Internet capability, and by simply having that enabled you require a privacy policy. If you aren't connecting to the Internet at all in your game, you should always ensure that none of the Internet options are enabled before you package your game. If you share any personal information, then you need to provide players with a method of opting in to the sharing. This could be done by gating the functionality behind a login screen. Note that this functionality can be locked away, and the requirement doesn't demand that you find a way to remain fully functional even if the user opts out. Features One requirement is that your game support both touch input and keyboard/mouse input. You can easily support this by using an input system like the one described in this article; however, by supporting touch input you get mouse input for free and technically fulfill this requirement. It's all about how much effort you want to put into the experience your player will have, and that's why including gamepad input is recommended as some players may want to use a connected Xbox 360 gamepad for their input device in games. Legacy APIs Although your game might run while using legacy APIs, it won't pass certification. This is checked through an automated test that also occurs during the WACK testing process, so you can easily check if you have used any illegal APIs. This often arises in third party libraries which make use of parts of the standard IO library such as the console, or the insecure versions of functions such as strcpy or fopen. Some of these APIs don't exist in WinRT for good reason; the console, for example, just doesn't exist, so calling APIs that work directly with the console makes no sense, and isn't allowed. Debug Another issue that may arise through the use of third-party libraries is that some of them may be compiled in debug mode. This could present issues at runtime for your app, and the packaging system will happily include these when compiling your game, unless it has to compile them itself. This is detected by the WACK and can be resolved by finding a release mode version, or recompiling the library. WACK The final tip is: run WACK. This kit quickly and easily finds most of the issues you may encounter during certification, and you see the issues immediately rather than waiting for it to fail during the certification process. Your final step before submitting to the store should be to run WACK, and even while developing it's a good idea to compile in release mode and run the tests to just make sure nothing is broken. Summary By now you should know how to submit your game to the store, and get through certification with little to no issues. We've looked at what you require for the store including imagery and metadata, as well as how to make use of the Windows Application Certification Kit to find problems early on and fix them up without waiting hours or days for certification to fail your game. One area unique to games that we have covered in this article is game ratings. If you're developing your game for certain markets where ratings are required, or if you are developing children's games, you may need to get a rating certificate, and hopefully you have an idea of where to look to do this. Resources for Article: Further resources on this subject: Introduction to Game Development Using Unity 3D [Article] HTML5 Games Development: Using Local Storage to Store Game Data [Article] Unity Game Development: Interactions (Part 1) [Article]
Read more
  • 0
  • 0
  • 4710
article-image-building-complete-board-based-puzzle-game-microsoft-xna-40
Packt
25 Sep 2010
14 min read
Save for later

Building a Complete Board-based Puzzle Game with Microsoft XNA 4.0

Packt
25 Sep 2010
14 min read
  XNA 4.0 Game Development by Example: Beginner's Guide Create your own exciting games with Microsoft XNA 4.0 Dive headfirst into game creation with XNA Four different styles of games comprising a puzzler, a space shooter, a multi-axis shoot 'em up, and a jump-and-run platformer Games that gradually increase in complexity to cover a wide variety of game development techniques Focuses entirely on developing games with the free version of XNA Packed with many suggestions for expanding your finished game that will make you think critically, technically, and creatively Fresh writing filled with many fun examples that introduce you to game programming concepts and implementation with XNA 4.0 A practical beginner's guide with a fast-paced but friendly and engaging approach towards game development Read more about this book (For more resources on XNA 4.0, see here.) It was just another day at the bottom of the ocean until an explosion in one of the storage bays cracked the protective dome around Deep Sea Research Lab Alpha. Now the entire place is flooding, and the emergency pump system is a chaotic jumble of loose parts. Designing a puzzle game The Puzzler has always been a popular game genre. From old standbys like Tetris to modern crazes like Bejeweled, puzzle games are attractive to players because they do not require a long-term time investment or a steep learning curve. The game mechanic is the heart of any good puzzle game. This mechanic is usually very simple, with perhaps a few twists to keep the players on their toes. In Flood Control, the player will be faced with a board containing 80 pieces of pipe. Some will be straight pipes and some will be curved. The objective of the game is to rotate the pipes to form a continuous line to pump water from the left side of the board to the right side of the board. Completing a section of pipe drains water out of the base and scores points for the player, but destroys the pipes used. New pipes will fall into place for the player to begin another row. Time for action - set up the Flood Control project Open Visual Studio Express Edition (If it is already open, select Close Solution from the File menu so you are starting with an empty slate). In the Visual Studio window, open the File menu and select New Project... Under Project Type, make sure XNA Game Studio 4.0 is selected. Under Templates, select Windows Game (4.0). Name the project Flood Control. Click on OK. Right-click on Flood ControlContent (Content) in the Solution Explorer window and select Add | New Folder. Name the folder Textures. Add another folder under Flood ControlContent (Content) and name the folder Fonts. Download the 0669_02_GRAPHICPACK.zip file from the book's code download link and extract the files to a temporary folder. Back in Visual Studio, right-click on Textures in the Content project and click on Add | Existing Item. Browse to the folder where you extracted the 0669_02_GRAPHICPACK files and highlight all of them. Click on Add to add them to your project. What just happened? You have now set up a workspace for building Flood Control, and created a couple of folders for organizing game content. You have also imported the sample graphics for the Flood Control game into the project. Introducing the Content Pipeline The Flood ControlContent (Content) project inside Solution Explorer is a special kind of project called a Content Project. Items in your game's content project are converted into .XNB resource files by Content Importers and Content Processors. If you right-click on one of the image files you just added to the Flood Control project and select Properties, you will see that for both the Importer and Processor, the Content Pipeline will use Texture - XNA Framework. This means that the Importer will take the file in its native format (.PNG in this case) and convert it to a format that the Processor recognizes as an image. The Processor then converts the image into an .XNB file which is a compressed binary format that XNA's content manager can read directly into a Texture2D object. There are Content Importer/Processor pairs for several different types of content—images, audio, video, fonts, 3D models, and shader language effects files. All of these content types get converted to .XNB files which can be used at runtime. In order to see how to use the Content Pipeline at runtime, let's go ahead and write the code to read these textures into memory when the game starts: Time for action - reading textures into memory Double-click on Game1.cs in Solution Explorer to open it or bring it to the front if it is already open. In the Class Declarations area of Game1 (right below SpriteBatch spriteBatch;), add: Texture2D playingPieces;Texture2D backgroundScreen;Texture2D titleScreen; Add code to load each of the Texture2D objects at the end of LoadContent(): playingPieces = Content.Load<Texture2D>(@"TexturesTile_Sheet");backgroundScreen = Content.Load<Texture2D>(@"TexturesBackground");titleScreen = Content.Load<Texture2D>(@"TexturesTitleScreen"); What just happened? In order to load the textures from disk, you need an in-memory object to hold them. These are declared as instances of the Texture2D class. A default XNA project sets up the Content instance of the ContentManager class for you automatically. The Content object's Load() method is used to read .XNB files from disk and into the Texture2D instances declared earlier. One thing to note here is that the Load() method requires a type identifier, specified in angled brackets (< >), before the parameter list. Known in C# as a "Generic", many classes and methods support this kind of type specification to allow code to operate on a variety of data types. We will make more extensive use of Generics later when we need to store lists of objects in memory. The Load() method is used not only for textures, but also for all other kinds of content (sounds, 3D models, fonts, etc.) as well. It is important to let the Load() method know what kind of data you are reading so that it knows what kind of object to return. Sprites and sprite sheets As far as XNA and the SpriteBatch class are concerned, a sprite is a 2D bitmapped image that can be drawn either with or without transparency information to the screen. Sprites vs. TexturesXNA defines a "sprite" as a 2D bitmap that is drawn directly to the screen. While these bitmaps are stored in Texture2D objects, the term "texture" is used when a 2D image is mapped onto a 3D object, providing a visual representation of the surface of the object. In practice, all XNA graphics are actually performed in 3D, with 2D sprites being rendered via special configurations of the XNA rendering engine. The simple form of the SpriteBatch.Draw() call when drawing squares only needs three parameters: a Texture2D to draw, a Rectangle indicating where to draw it, and a Color to specify the tint to overlay onto the sprite. Other overloads of the Draw() method, however, also allow you to specify a Rectangle representing the source area within the Texture2D to copy from. If no source Rectangle is specified, the entire Texture2D is copied and resized to fit the destination Rectangle. OverloadsWhen multiple versions of the same method are declared with either different parameters lists or different return values, each different declaration is called an "overload" of the method. Overloads allow methods to work with different types of data (for example, when setting a position you could accept two separate X and Y coordinates or a Vector2 value), or leave out parameters that can then be assigned default values. By specifying a source Rectangle, however, individual pieces can be pulled from a large image. A bitmap with multiple sprites on it that will be drawn this way is called a "sprite sheet". The Tile_Sheet.png file for the Flood Control project is a sprite sheet containing 13 different sprites that will be used to represent the pieces of pipe used in the game. Each image is 40 pixels wide and 40 pixels high, with a one pixel border between each sprite and also around the entire image. When we call SpriteBatch.Draw() we can limit what gets drawn from our texture to one of these 40 by 40 squares, allowing a single texture to hold all of the playing piece images that we need for the game: The Tile_Sheet.png file was created with alpha-based transparency. When it is drawn to the screen, the alpha level of each pixel will be used to merge that pixel with any color that already occupies that location on the screen. Using this fact, you can create sprites that don't look like they are rectangular. Internally, you will still be drawing rectangles, but visually the image can be of any shape. What we really need now to be able to work with the playing pieces is a way to reference an individual piece, knowing not only what to draw to the screen, but what ends of the pipe connect to adjacent squares on the game board. Alpha blendingEach pixel in a sprite can be fully opaque, fully transparent, or partially transparent. Fully opaque pixels are drawn directly, while fully transparent pixels are not drawn at all, leaving whatever has already been drawn to that pixel on the screen unchanged. In 32-bit color mode, each channel of a color (Red, Green, Blue, and Alpha) are represented by 8 bits, meaning that there are 256 different degrees of transparency between fully opaque (255) and fully transparent (0). Partially transparent pixels are combined with the current pixel color at that location to create a mixed color as if the pixels below were being seen through the new color. Classes used in Flood Control While it would certainly be possible to simply pile all of the game code into the Game1 class, the result would be difficult to read and manage later on. Instead, we need to consider how to logically divide the game into classes that can manage themselves and help to organize our code. A good rule of thumb is that a class should represent a single thing or type of thing. If you can say "This object is made up of these other objects" or "This object contains these objects", consider creating classes to represent those relationships. The Flood Control game contains a game board made up of 80 pipes. We can abstract these pipes as a class called GamePiece, and provide it with the code it needs to handle rotation and provide the code that will display the piece with a Rectangle that can be used to pull the sprite off the sprite sheet. The game board itself can be represented by a GameBoard class, which will handle managing individual GamePiece objects and be responsible for determining which pieces should be filled with water and which ones should be empty. The GamePiece class The GamePiece class represents an individual pipe on the game board. One GamePiece has no knowledge of any other game pieces (that is the responsibility of the GameBoard class), but it will need to be able to provide information about the pipe to objects that use the GamePiece class. Our class has the following requirements: Identify the sides of each piece that contain pipe connectors Differentiate between game pieces that are filled with water and that are empty Allow game pieces to be updated Automatically handle rotation by changing the piece type to the appropriate new piece type Given one side of a piece, provide the other sides of the piece in order to facilitate determining where water can flow through the game board Provide a Rectangle that will be used when the piece is drawn, to locate the graphic for the piece on the sprite sheet Identifying a GamePiece While the sprite sheet contains thirteen different images, only twelve of them are actual game pieces (the last one is an empty square). Of the twelve remaining pieces, only six of them are unique pieces. The other six are the water-filled versions of the first six images. Each of the game pieces can be identified by which sides of the square contain a connecting pipe. This results in two straight pieces and four pieces with 90 degree bends in them. A second value can be tracked to determine if the piece is filled with water or not instead of treating filled pieces as separate types of pieces. Time for action - build a GamePiece class - declarations Switch back to your Visual C# window if you have your image editor open. Right-click on Flood Control in Solution Explorer and select Add | Class... Name the class GamePiece.cs and click on Add. At the top of the GamePiece.cs file, add the following to the using directives already in the class: using Microsoft.Xna.Framework.Graphics;using Microsoft.Xna.Framework; In the class declarations section, add the following: public static string[] PieceTypes = { "Left,Right", "Top,Bottom", "Left,Top", "Top,Right", "Right,Bottom", "Bottom,Left", "Empty"};public const int PieceHeight = 40;public const int PieceWidth = 40;public const int MaxPlayablePieceIndex = 5;public const int EmptyPieceIndex = 6;private const int textureOffsetX = 1;private const int textureOffsetY = 1;private const int texturePaddingX = 1;private const int texturePaddingY = 1;private string pieceType = "";private string pieceSuffix = ""; Add two properties to retrieve information about the piece: public string PieceType{ get { return pieceType; }}public string Suffix{ get { return pieceSuffix; }} What just happened? You have created a new code file called GamePiece.cs and included the using statements necessary to access the pieces of the XNA Framework that the class will use. Using DirectivesAdding the XNA Framework using directives at the top of the class file allows you to access classes like Rectangle and Vector2 without specifying their full assembly names. Without these statements, you would need Microsoft.Xna.Framework.Rectangle in your code every time you reference the type, instead of simply typing Rectangle. In the declarations area, you have added an array called PieceTypes that gives a name to each of the different types of game pieces that will be added to the game board. There are two straight pieces, four angled pieces, and an empty tile with a background image on it, but no pipe. The array is declared as static because all instances of the GamePiece class will share the same array. A static member can be updated at execution time, but all members of the class will see the same changes. Then, you have declared two integer constants that specify the height and width of an individual playing piece in pixels, along with two variables that specify the array index of the last piece that can be placed on the board (MaxPlayablePieceIndex) and of the fake "Empty" piece. Next are four integers that describe the layout of the texture file you are using. There is a one pixel offset from the left and top edge of the texture (the one pixel border) and a single pixel of padding between each sprite on the sprite sheet. Constants vs. Numeric literalsWhy create constants for things like PieceWidth and PieceHeight and have to type them out when you could simply use the number 40 in their place? If you need to go back and resize your pieces later, you only need to change the size in one place instead of hoping that you find each place in the code where you entered 40 and change them all to something else. Even if you do not change the number in the game you are working on, you may reuse the code for something else later and having easily changeable parameters will make the job much easier. There are only two pieces of information that each instance of GamePiece will track about itself—the type of the piece and any suffix associated with the piece. The instance members pieceType and pieceSuffix store these values. We will use the suffix to determine if the pipe that the piece represents is empty or filled with water. However, these members are declared as private in order to prevent code outside the class from directly altering the values. To allow them to be read but not written to, we create a pair of properties (pieceType and pieceSuffix) that contain get blocks but no set blocks. This makes these values accessible in a read-only mode to code outside the GamePiece class.
Read more
  • 0
  • 0
  • 4709

article-image-benchmarking-and-optimizing-go-code-part-1
Alex Browne
16 Mar 2015
6 min read
Save for later

Benchmarking and Optimizing Go Code, Part 1

Alex Browne
16 Mar 2015
6 min read
In this two part post, you'll learn the basics of how to benchmark and optmize go code. You'll do this by trying out a few different implementations for calculating a specific element in Pascal's Triangle (a.k.a. the binomial coeffecient). I'll assume that you are already familiar with go, but if you aren't, I recommend the interactive tutorial. All of the code for these two posts is available on github. Installation & Set Up To follow along, you will need to install go version 1.2 or later. Also, make sure that you follow these instructions for setting up your go work environment. In particular, you will need to have the GOPATH environment variable pointing to a directory where all your go code will reside. The Goal Our goal is to write a function to calculate a specific element of Pascal's Triangle. In case you aren't familiar with Pascal's Triangle, it looks something like this: Pascal's Triangle follows these simple rules: The first row contains a single element (1) Every subsequent element is the sum of the two elements directly above it (one above and to the left, and the other above and to the right). If either the element above and to the left or the one above and to the right are absent, consider them to be equal to zero. For convenience, we'll index all of the rows and columns in Pascal's Triangle, starting with 0. So the element at the very top of the triangle is at index (0, 0). The element at index (4, 1) would be at row 4 and column 1, which is 1 + 3 = 4. The function we'll be writing will return the element at row n, column m of Pascal's Triangle and has the following signature: func Pascal(n, m int) int So Pascal(0, 0) should return 1 and Pascal(5, 2) would return 10. In these posts, we'll write several different implementations of the Pascal function, test each one for correctness, and benchmark them to see which is the fastest. Project Structure Now's a good time to setup the directory where your code for this project will reside. Somehwere in $GOPATH/src, create a new directory and call it whatever you want. I recommend $GOPATH/src/github.com/your-github-username/go-benchmark-example. Our basic project structure is going to look like this: go-benchmark-example common common.go implementations builtin.go naive.go recursive.go test benchmark_test.go pascal_test.go The implementations package will hold a few different implementations of the Pascal function, each in their own file. The test package is where we will test the implementations for corectness (in pascal_test.go) and then benchmark their performance (in benchmark_test.go). Without further ado, let's start writing code! The Pascaler Interface To make comparing different implementations easier, we'll create an interface that all of the implementations should implement. (You'll see why this is handy when we write the tests and benchmarks). Add the following to common/common.go: package common type Pascaler interface { Pascal(int, int) int } That's it! All we've done is declare an interface that consists of one method, Pascal, which takes two ints as arguments (the row and column) and returns the value of the specified element in Pascal's Triangle. The seemingly odd name "Pascaler" is just the convention in go for an interface with only one method. Naive Implementation The first implementation we'll write is a naive iterative one. The basic idea is to generate the triangle from top to bottom until we reach row n and column m. We call this implementation "naive" because it does not attempt to do anything clever and will probably not perform the best. Add the following to implementations/naive.go: package implementations type naiveType struct{} var Naive = naiveType{} func (p naiveType) Pascal(n, m int) int { // Instantiate a slice to hold n+1 rows rows := make([][]int, n+1) // Start by hard-coding the first two rows if n < 2 { rows = make([][]int, 2) } rows[0] = []int{1} rows[1] = []int{1, 1} // Iterate from top to bottom until we reach row n for i := 2; i <= n; i++ { numColumns := i + 1 rows[i] = make([]int, numColumns) rows[i][0] = 1 rows[i][numColumns-1] = 1 for j := 1; j < numColumns-1; j++ { // Element (i, j) is equal to the sum of the two elements // directly above it rows[i][j] = rows[i-1][j-1] + rows[i-1][j] } } return rows[n][m] } // Implement the Stringer interface so we can print the Naive // object directly with fmt.Print and friends func (p naiveType) String() string { return "Naive Implementation" } Testing for Correctness The next thing we'll do is test our implementation to make sure it is correct. Since we want to test each implementation the same way, we'll write a small utility function called testPascaler, which takes a Pascaler as an argument. The function will iterate through an array of test cases and run each case against the given implementation. Add the following to test/pascal_test.go: import ( "github.com/albrow/go-benchmark-example/common" "github.com/albrow/go-benchmark-example/implementations" "reflect" "testing" ) func TestNaive(t *testing.T) { testPascaler(t, implementations.Naive) } // testPascaler can be used to test any implementation. It uses a // series of test cases and reports any errors using t.Error. func testPascaler(t *testing.T, p common.Pascaler) { // cases is an array of test cases, each consisting of two inputs // n and m and the expected output. cases := []struct { n int m int expected int }{ {0, 0, 1}, {1, 0, 1}, {1, 1, 1}, {4, 1, 4}, {6, 4, 15}, {7, 3, 35}, {7, 0, 1}, {7, 7, 1}, {32, 16, 601080390}, {64, 32, 1832624140942590534}, } // Iterate through each test case and check the result for _, c := range cases { if reflect.TypeOf(p) == reflect.TypeOf(implementations.Recursive) && c.n > 30 { // Skip cases where n is too large for the recursive implementation. // It takes too long and might even timeout. continue } got := p.Pascal(c.n, c.m) if got != c.expected { t.Errorf("Incorrect result for %s with inputs (%d, %d).nExpected %d but got %d.", p, c.n, c.m, c.expected, got) } } } To run the test, just run the following command from your project directory: go test ./.... If everything works as expected and the test passes, you should see the following output: ? github.com/albrow/go-benchmark-example/common [no test files] ? github.com/albrow/go-benchmark-example/implementations [no test files] ok github.com/albrow/go-benchmark-example/test 0.005s Conclusion Follow along in Part 2 where we will cover benchmarking for performance, a recursive implementation, and a bultin implementation. About the Author Alex Browne is a programmer and entrepreneur with about 4 years of product development experience and 3 years experience working on small startups. He has worked with a wide variety of technologies and has single-handedly built many production-grade applications. He is currently working with two co-founders on an early stage startup exploring ways of applying machine learning and computer vision to the manufacturing industry.His favorite programming language is Go.
Read more
  • 0
  • 0
  • 4706
Modal Close icon
Modal Close icon