Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

7018 Articles
article-image-cache-replication
Packt
19 Aug 2013
5 min read
Save for later

Cache replication

Packt
19 Aug 2013
5 min read
(For more resources related to this topic, see here.) Ehcache replication using RMI The Ehcache framework provides RMI (Remote Method Invocation) based cache replication across the cluster. It is the default implementation for replication. The RMI-based replication works on the TCP protocol. Cached resources are transferred using the serialization and deserialization mechanism of Java. RMI is a point-to-point protocol and hence, it generates a lot of network traffic between clustered nodes. Each node will connect to other nodes in the cluster and send cache replication messages. Liferay provides Ehcache replication configuration files in the bundle. We can re-use them to set up Ehcache replication using RMI. Let's learn how to configure Ehcache replication using RMI for our cluster. Stop both the Liferay Portal nodes if they are running. Add the following properties to the portal-ext.properties file of both the Liferay Portal nodes: net.sf.ehcache.configurationResourceName=/ehcache/hibernate-clustered.xmlnet.sf.ehcache.configurationResourceName.peerProviderProperties=peerDiscovery=automatic,multicastGroupAddress=${multicast.group.address["hibernate"]},multicastGroupPort=${multicast.group.port["hibernate"]},timeToLive=1ehcache.multi.vm.config.location=/ehcache/liferay-multi-vm-clustered.xmlehcache.multi.vm.config.location.peerProviderProperties=peerDiscovery=automatic,multicastGroupAddress=${multicast.group.address["multi-vm"]},multicastGroupPort=${multicast.group.port["multi-vm"]},timeToLive=1multicast.group.address["hibernate"]=233.0.0.4multicast.group.port["hibernate"]=23304multicast.group.address["multi-vm"]=233.0.0.5multicast.group.port["multi-vm"]=23305 Now restart both the Liferay Portal nodes. Liferay Portal uses two separate Ehcache configurations for the hibernate cache and the Liferay service layer cache. Liferay ships with two different sets of configuration files for each hibernate and service layer cache. By default, it uses the non-replicated version of the cache file. Using the portal-ext.properties file, we can tell Liferay to use the replicated cache configuration file. In the preceding steps, we configured the replicated version of cache files for both the hibernate and service layer cache using the net.sf.ehcache.configurationResourceName and ehcache.multi.vm.config.location properties. Replicated Ehcache configuration files internally use IP multicast to establish the RMI connection between each Liferay node. We configured IP multicast and ports for establishing connections. Ehcache configuration using JGroups Another option to replicate Ehcache is using JGroups. JGroups is a powerful framework used for multicast communication. The Ehcache framework also supports replication using JGroups. Similar to the RMI-based Ehcache replication, Liferay also supports JGroup-based replication. Let's learn how to configure the JGroup-based Ehcache replication. Stop both the Liferay Portal nodes if they are running. Add the following properties to the portal-ext.properties file of both the Liferay Portal nodes: ehcache.multi.vm.config.location=/ehcache/liferay-multi-vm-clustered.xmlehcache.multi.vm.config.location.peerProviderProperties=connect=UDP(mcast_addr=multicast.group.address["hibernate"];mcast_port=multicast.group.port["hibernate"];):PING:MERGE2:FD_SOCK:VERIFY_SUSPECT:pbcast.NAKACK:UNICAST:pbcast.STABLE:FRAG:pbcast.GMSehcache.bootstrap.cache.loader.factory=com.liferay.portal.cache.ehcache.JGroupsBootstrapCacheLoaderFactoryehcache.cache.event.listener.factory=net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactorynet.sf.ehcache.configurationResourceName=/ehcache/hibernate-clustered.xmlnet.sf.ehcache.configurationResourceName.peerProviderProperties=peerDiscovery=connect=UDP(mcast_addr=multicast.group.address["multi-vm"];mcast_port=multicast.group.port["multi-vm"];):PING:MERGE2:FD_SOCK:VERIFY_SUSPECT:pbcast.NAKACK:UNICAST:pbcast.STABLE:FRAG:pbcast.GMSmulticast.group.address["hibernate"]=233.0.0.4multicast.group.port["hibernate"]=23304multicast.group.address["multi-vm"]=233.0.0.5multicast.group.port["multi-vm"]=23305 Now restart both the nodes one by one to activate the preceding configuration. The Ehcache replication configuration is very similar to the RMI-based replication. Here, we used the UDP protocol to connect Liferay Portal nodes. With this option both Liferay Portal nodes also connect with each other using IP multicast. Ehcache replication using Cluster Links We learned about the JGroups- and RMI-based Ehcache replication. The Liferay Enterprise version includes another powerful feature called Cluster Link, which provides the Ehcache replication mechanism. Internally, this feature uses JGroups to replicate the cache across the network. Let's go through the steps to configure this feature. Stop both the Liferay Portal nodes if they are running. Now deploy the ehcache-cluster-web enterprise plugin on both the Liferay Portal servers. Now, edit portal-ext.properties of both the nodes: cluster.link.enabled=trueehcache.cluster.link.replication.enabled=truenet.sf.ehcache.configurationResourceName=/ehcache/hibernate-clustered.xmlehcache.multi.vm.config.location=/ehcache/liferay-multi-vm-clustered.xml Now restart both the Liferay Portal servers to activate this configuration. Unlike the JGroups- or RMI-based Ehcache replication, this option centralizes all Ehcache changes at one place and then distributes changes to all the nodes of the cluster. This in turn reduces unnecessary network transfers. This option is only available in the Liferay Enterprise version. Hence, the preceding steps are applicable only if you are using the Liferay Enterprise version. Ehcache clustering best practices We talked about different options to configure Ehcache replication. Let's learn the best practices related to Ehcache replication. If there are more than two nodes in the cluster, it is recommended to either use Cluster Link- or JGroups-based replication. If we are using the Liferay Enterprise edition, it is recommended to use Cluster Link for Ehcache replication. All three options that we discussed previously use IP multicast for establishing connections with other nodes. The IP multicast technique uses group IP and port to know other nodes in the same group. It is very important to ensure that the same IP and port are used by the nodes of the same cluster. It is advisable to keep the group IP and port different for development, testing, or staging environment to make sure that the nodes of other environments do not pair up with the production environment. Cluster Link provides up to 10 transport channels to transfer cached resources across the cluster. If the application is supposed to have a huge cache and frequent cache changes, it is advisable to configure multiple transport channels using the cluster.link.channel.properties.transport configuration property. Summary We learned about various configuration options for implementing clustering. Resources for Article: Further resources on this subject: Liferay, its Installation and setup [Article] Setting up and Configuring a Liferay Portal [Article] Vaadin Portlets in Liferay User Interface Development [Article]
Read more
  • 0
  • 0
  • 3921

article-image-biztalk-esb-management-portal
Packt
19 Aug 2013
6 min read
Save for later

BizTalk: The ESB Management Portal

Packt
19 Aug 2013
6 min read
(For more resources related to this topic, see here.) Registering services in UDDI Thanks to the ESB Toolkit, we can easily populate our organization's services registry in UDDI with the services that interact with the ESB, either because the ESB exposes them or because they can be consumed through it. Before we can register service in UDDI we must first configure the registry settings. Registry settings The registery settings change how the UDDI registration functionality mentioned in preceding section behaves. UDDI Server: This sets URL of the UDDI server. Auto Publish: When enabled, any registry request will be automatically published. If it's disabled, the requests will require administrative approval. Anonymous: This setting indicates whether to use anonymous access to connect to the UDDI server or to use the UDDI Publisher Service account. Notification Enabled: This enables or disables the delivery of notifications when any registry activity occurs on the portal. SMTP Server: This is the address of the SMTP server that will send notification e-mail messages. Notification E-Mail: This is the e-mail address to which to send endpoint update notification e-mail messages. E-Mail From Address: This is the address that will show up as sender in notification messages sent. E-Mail Subject: This is the text to display in the subject line of notification e-mail messages. E-Mail Body: This is the text for the body of notification e-mail messages. Contact Name: This setting is name of the UDDI administrator to notify of endpoint update requests. Contact E-Mail: This setting is used for the e-mail address of the UDDI administrator for notifications of endpoint update requests. The following screenshot shows all of the settings mentioned in preceding list: In the ESB Management Portal, we can see in the top menu an entry that takes us to the Registry functionality, shown in the following screenshot: On this view, we can directly register a service into UDDI. To do this, first we have to search the endpoint that we want to publish. These can be endpoints of services that the ESB consumes through Send ports, or endpoints of services that the ESB exposes through receive locations. As an example, we will publish one of the services exposed by the ESB through the GlobalBank.ESB sample application that comes with the ESB Toolkit. First, we will search on the New Registry Entry page for the endpoints in the GlobalBank.ESB application, as shown in the following screenshot: Once we get the results, we will click on the Publish link of the DynamicResolutionReqResp_SOAP endpoint that actually exposes the /ESB. NorthAmericanServices/CustomerOrder.asmx service. We will be presented with a screen where we can fill in further details about the service registry entry, such as the service provider under which we want to publish the service (or we can even create a new service provider that will get registered in UDDI as well). After clicking on the Publish button at the bottom of the page, we will be directed back to the New Registry Entry screen, where we can filter again and see how our new registry entry is in Pending status, as it needs to be approved by an administrator. We can access the Manage Pending Requests module through the corresponding submenu under the top-level Registry menu. There we can see if there are any new registry entries that might be pending for approval. By using the buttons to the left of each item, we can view the details of the request, edit them, and approve or delete the request. Once we approve the request, we will receive a confirmation message on the portal telling us that it got approved. Then, we can go to the UDDI portal and look for the service provider that we just created, were we will see that our service got registered. The following screenshot shows how the service provider of the service we just published is shown in the UDDI portal: In the following screenshot we can see the actual service published, with its corresponding properties. With these simple steps, we can easily build our own services registry in UDDI based on the services our organization already has, so they can be used by the ESB or any other systems to discover services and know how to consume them. Understanding the Audit Log Audit Log is a small reporting feature that is meant to provide information about the status of messages that have been resubmitted to the ESB through the resubmission module. We can access this module through the Manage Audit Log menu. We will be presented with a list of the messages that were resubmitted, if those were resubmitted successfully or not, and even check the actual message that was resubmitted, as the message could have been modified before being resubmitted. Fault Settings On the Fault Settings page we can specify: Audit Options: This includes the type events that we want to audit: Audit Save: When a message associated with a fault is saved. Audit Successful Resubmit: When a message is successfully resubmitted. Audit Unsuccessful Resubmit: When the resubmission of a message fails. Alert Queue Options: Here we can enable or disable the queuing of the notifications generated when a fault message is published to the portal. Alert Email Options: Here we can enable and configure the service that will actually send e-mail notifications once fault messages are published to the portal. The three most important settings in this section are: Email Server: The e-mail server that will be actually used to send the e-mails. Email From Address: The address that will show up as sender in the e-mails sent. Email XSLT File Absolute Path: The XSLT transformation sheet that will be used to format the e-mails. The ESB Toolkit provides one, but we could customize it or create our own sheet according to our requirements. Summary In this article, we discussed the additional features of the ESB Management Portal. We learned about the registry settings, which are used for configuring the UDDI and setting up the e-mail notifications. We also learned how to configure fault settings and how to utilize the Audit Log features. Resources for Article : Further resources on this subject: Microsoft Biztalk server 2010 patterns: Operating Biztalk [Article] Setting up a BizTalk Server Environment [Article] Communicating from Dynamics CRM to BizTalk Server [Article]
Read more
  • 0
  • 0
  • 5977

article-image-setting-civicrm
Packt
19 Aug 2013
11 min read
Save for later

Setting Up CiviCRM

Packt
19 Aug 2013
11 min read
(For more resources related to this topic, see here.) Setting up a CiviCRM theme in Drupal CiviCRM administration screens take up a lot of browser real estate. How CiviCRM looks is determined by what themes you are using in your CMS. Problems arise when you use your main website theme to display CiviCRM pages. All the customizations, blocks of information, and layouts suddenly get in the way when you want to administer CiviCRM. The trick is to use a different theme for CiviCRM. How to do it… This is very easy to accomplish, and just uses a configuration screen in Drupal. Make sure you have the CiviCRM theme module enabled. Navigate to admin/appearance in Drupal by clicking on the Appearance button. This page shows the themes that are currently installed within our CMS—in this case, Drupal. Make sure that any themes you wish to use are enabled. At the foot of the screen, configure CiviCRM Administration theme. How it works… Drupal uses the page URL to check if you are administering CiviCRM. If you are, the pages are displayed using the CiviCRM administration theme. It's a good idea to select a flexible-width theme with sidebars. Garland is a good example. The flexible width accommodates CiviCRM displays nicely. Once the administration theme is selected, navigate to admin/structure/blocks. Here you will see various blocks provided by the CiviCRM module. You can now place these blocks within your administrative theme. Pay special attention to the visibility settings for these blocks, so that they only appear when using CiviCRM. There's more… In Drupal, there is an additional setting that controls which theme is used to display public CiviCRM pages, for example, event sign-up pages. See also You can explore hundreds of contributed Drupal themes at http://drupal.org/project/themes Setting up cron using cPanel Cron is a time-based scheduler that is used extensively throughout CiviCRM. For example, you might want to use CiviCRM to send out an e-mail newsletter at a particular time, or you might want to send out a reminder to participants to attend an event. CiviCRM has settings to accomplish all these tasks, but these, in turn, rely on having "master" cron set up. Cron is set up on your web server, not within CiviCRM. How to do it… There are many different ways of setting up cron, depending on your site-hosting setup. In this example, we are using cPanel, a popular control panel that simplifies website administration. Make a note of your CMS site administrator username and password. Make a note of your CiviCRM site key, which is a long string of characters used to uniquely identify your CiviCRM installation. It is automatically generated when CiviCRM is installed, and is stored in the civicrm_settings.php file. Using a text editor, open up the CiviCRM settings file located at /sites/default/civicrm_settings.php. Around line 170, you will see the following entry: define( 'CIVICRM_SITE_KEY', '7409e83819379dc5646783f34f9753d9' ); Make a note of this key. Log in to cPanel and use the cPanel File Manager to explore the folders and files that are stored there. You are going to create a file that contains all the necessary information for cron to work. You can choose to create the cron file anywhere you like. It makes sense to keep it in the home directory of your webserver—that is, the first directory you get to once you start exploring. Create a file called CiviCron.php. The naming does not particularly matter, but it must be a PHP file. Insert the following code: <?php// create a new cURL resource$ch = curl_init();// set URL and other appropriate optionscurl_setopt($ch, CURLOPT_URL, "http://myDrupalsite.com/sites/all/modules/civicrm/bin/ cron.php?name=admin&pass=adminpassword&key =01504c43af550a317f3c6495c2442ab7");curl_setopt($ch, CURLOPT_HEADER, 0);// grab URL and pass it to the browsercurl_exec($ch);curl_close($ch);?> Substitute http://myDrupalsite.com with your own domain Substitute admin with your own CMS admin username Substitute adminpassword with your own CMS admin password Substitute the key value with the site key from civicrm_settings.php Save this file and then navigate to cron in cPanel. Select an appropriate cron interval from the Common Settings list. Choosing an appropriate cron interval may take some experimentation, depending on how your site is set up. In the Command field, enter the following address: php /home/site_account_name/public_html/CiviCron.php The portion after php is the absolute path to the CiviCron.php file you created in step 4. Click on Add New Cron Job. How it works… All cron does is execute the URL that is constructed in the cron file. The following piece of code does the work: curl_setopt($ch, CURLOPT_URL, "http://myDrupalsite.com/sites/all/modules/civicrm/bin/ cron.php?name=admin&pass=adminpassword&key= 01504c43af550a317f3c6495c2442ab7"); The URL contains the information on permissions (the username, the password, and the site key) to execute the cron.php file provided by the CiviCRM module. Getting cron to work is critical to getting CiviCRM working properly. If you get into difficulties with it, the best solution is to contact your hosting company and seek guidance. To test that your cron job is actually working, carry out the following instructions. In the cPanel cron screen, set it to send you an e-mail each time the cron command is run. The e-mail will contain an error message if the cron fails. Failures are generally due to an incorrect setting of the path, or a permissions problem with the username, password, or site key. Adding items to the CiviCRM navigation menu As you begin to use CiviCRM, you will want to provide administrative shortcuts. You can do this by adding custom menu blocks within your CMS or editing the navigation menu in CiviCRM. How to do it… CiviCRM has a fully customizable navigation menu. You can edit this menu to get one-click access to the features you use most. Navigate to a page that you want to use as the link destination for a menu item. For example, you could navigate to Contacts | Manage Groups , and then select a suitable group. Copy the page URL in the browser location. In this example, it would be as follows: civicrm/group/search?reset=1&force=1&context=smog&gid=2 Navigate to Administer | Customize Data and Screens | Navigation Menu. This displays the CiviCRM navigation menu in tree form. Click on the left arrow on each Parent menu item to expand it. You can now explore all the child menu items. Click on the Add Menu item button at the top of this screen. This brings up the Add Menu Item edit screen. Enter the name of the menu item in the Title field Enter the URL (that you copied) into the URL field. Select a parent to make the menu item appear as the child of another menu item. If you don't select a parent, the item will appear on the main CiviCRM menu bar. Select one or more permissions in the Permission field to control who can use the menu item. These are CMS permissions, so we must ensure that these are set correctly in our CMS for the menu item to behave properly. How it works… CiviCRM stores new menu items, and displays them according to where they are placed in the menu tree and what permissions a user may have to use them. See also You can fully explore CiviCRM customization at http://book.civicrm.org/user/current/initial-set-up/customizing-the-user-interface/ Refreshing the dashboard By default, CiviCRM sets the auto-refresh period for the home page dashboard to 1 hour. In a busy setting, this is too long, and you constantly have to click on the Refresh Dashboard data button to get the information on the dashboard up to date. How to do it… Changing the setting is simply a matter of visiting the CiviCRM administration pages: Navigate to Administer | System Settings | Undelete, Logging and ReCAPTCHA. Change the Dashboard cache timeout value from 1440 (that's 1 hour in seconds) to a smaller figure. Changing display preferences By default, CiviCRM displays a lot of data on the contact summary screen. Sometimes, this can lead to a cluttered display that is hard to use and slow to load. How to do it… CiviCRM components can add to the clutter on the screen. Here we can disable unwanted components and then fine-tune the display of other elements in the contact summary screen. Navigate to Administer | System Settings | Enable CiviCRM Components, and disable any unused CiviCRM components. Navigate to Administer | Customize data and screens | Display preferences. Control which tabs are displayed in the detail screen (for each contact), using the checkboxes. Control which sections you want to see when editing an individual contact, by checking the checkboxes in the Editing Contacts section. Drag the double-arrow icon to move the sections up and down the contact editing screen. See also You can fully explore the display preferences at http://book.civicrm.org/user/current/initial-set-up/customizing-the-user-interface/ Replacing words This is useful for fine-tuning your website. For example, you could replace US spelling with UK spelling (thus avoiding installing the UK language translation). Or you might want to change the wording on parts of a standard form without having to make a custom template. How to do it… The words—or sentences—that we want to replace are called strings. In CiviCRM, we can enter the strings we don't want, and replace them with strings we do want. Navigate to Administer | System Settings | Customize Data and Screens | Word Replacement. In this example, I am replacing the US spelling of "Organization" with the UK version, "Organisation". Use the Exact Match checkbox to match words precisely. This would then exclude plurals of the word from being matched. All word replacements are case sensitive. Setting up geocoding Geocoding allows you to do location-based searching and to display the maps of contacts. How to do it… You need to set a mapping provider—that is a service that will provide you with the visual maps—and a geocoding provider, which will translate your contact addresses into latitude and longitude coordinates. Navigate to Administer | Localization | Address settings. In Address Display, make sure that the Street Address Parsing checkbox is ticked. Navigate to Administer | System Settings | Mapping and Geocoding. Set Mapping Provider to Google or Openstreetmap. Set Geocoding Provider to Google. Navigate to Administer | System Settings | Scheduled Jobs. The Geocode and Parse Addresses scheduled job should now be enabled. You can set how regularly you want CiviCRM to geocode your address data. How it works… Geocoding Provider finds latitude and longitude coordinates for each contact address. Mapping Provider uses this information to draw a local map, with a pointer for the contact. Geocode and Parse Addresses do the geocoding work each day, though you can change this in the settings. There's more… Google currently limits geocoding requests to 2,500 per 24 hours. So, if you exceed this limit, Google may not process requests; it may even restrict access to their geocoding service should you continue to break this limit. This is a problem when you have thousands of addresses to process—for example, after a big import of address data. CiviCRM does not have a tool to place a daily limit on the number of contacts that are processed each day. But you can put parameters into the Geocode and Parse Addresses scheduled job that provide a range of contact IDs to process. You would have to change this each day to work your way though all your contacts. Navigate to Administer | System Settings | Scheduled Jobs, and edit the Geocode and Parse Addresses scheduled job. In the Command Parameters box, enter: start= 1end=2500 1 would be the ID of your first contact. If you have access to your database tables, check the database table civicrm_contact to know what the first value for your contacts is. See also Further details about geocoding in CiviCRM are available at http://wiki.civicrm.org/confluence/display/CRMDOC43/Mapping+and+Geocoding
Read more
  • 0
  • 0
  • 2405

article-image-creating-new-forum
Packt
19 Aug 2013
6 min read
Save for later

Creating a new forum

Packt
19 Aug 2013
6 min read
(For more resources related to this topic, see here.) In the WordPress Administration, click on New Forum, which is a subpage of the Forums menu item on the sidebar. You will be taken to a screen that is quite similar to a WordPress post creation page, but slightly different with a few extra areas: If you are not familiar with the WordPress post creation page, the following is a list of the page's features: The Enter Title Here box The long box on the top of the page is your forum title. This, on the forum page, will be what is clicked on, and will also provide the basis for the forum's URL Slug with some changes, as URL Slugs generally have to be letters, numbers, and dashes. So for example, if your forum title is My Product's Support Section, your Slug will probably be my-products-support-section. When you insert the forum title, the URL Slug will be generated below. However, if you wish to change it, click on the yellow highlighted section to change the Slug, and then click on OK. The Post box Beneath the title box is the post box. This should contain your forum description. This will be shown beneath your forum's name on the forum index page. You can add rich text to this, such as bold or italicized text, but my advice is to keep this short. One or two lines of text would suffice, otherwise it could make your forum look peculiar. Forum attributes Towards the right-hand side of the screen, you should see a Forum Attributes section. bbPress allows to set a number of different attributes for your created forum. The attributes are explained in detail as follows: Forum type: Your forum can be one of two types: "Forum" or "Category". Category is a section of the site where you cannot post, but forums are grouped in. So for example, if you have forums for "Football", "Cricket", and "Athletics", you may group them into a "Sport" category. Unless you have a large forum with a number of different areas, you shouldn't need many categories. Normally you would begin with a few forums, but then as your forums grow, you would introduce categories. If you create a category, any forum you create must be a subforum of the category. We will talk about creating subforums later in this article. Status: Your forum's status indicates if other users can post in the forum. If the status is "Open", any user can post in the forum. If the forum is "Closed", nobody can contribute other than Keymasters. Unless one of your forums is a "Forum Rules" forum, you would probably keep all forums as Open. Visibility: bbPress allows three types of forum visibility . These, as the names suggest, decide who gets to see the forums. The three options are as follows: Public: This type allows anybody visiting the site to see the forum and its contents. Private: This type allows users who are logged in to view and contribute to the forum, but the forum is hidden from users that are not logged in or users that are blocked. Private forums are prefixed with the word "Private". Hidden: This type allows only Moderators and Keymasters to view the forum. Most forums will probably have majority of their forums set to Public, but have selections that are Private or Hidden. Usually, having a Hidden forum to discuss forum matters with Administrators or Moderators is a good thing. You can have a private forum as well that could help encourage people to register on the site. Parent: You can have subforums of forums. By giving a parent to the forum, you make it a subforum. An example of this would be if you had a "Travel" forum, you can have subforums dedicated to "Europe", "Australia", and "Asia". Again, you will probably start with just a few forums, but over time, you will probably grow your forum to include subforums. Order: The Order field helps define the order in which your forums are listed. By default, or if unspecified, the order is always alphabetical. However, if you give a number, then the order of the forum will be determined by the Order number, from smallest to largest. It is good to put important forums at the top, and less important forums towards the bottom of the page. It's a good idea to number your orders in multiples of 10, rather than 1, 2, 3, and so on. That way, if you want to add a forum to your site that will be between two other forums, you can add it in with a number between the two multiples of 10, thus saving time. Now that you have set up a forum, click on publish, and congratulations, you should have a forum! Editing and deleting forums Forums are a community, and like all good communities, they evolve over time depending on their user's needs. As such, over time, you may need to restructure or delete forums. Luckily, this is easily done. First, click on Forums in the sidebar of the WordPress Administration. You should see a list of all the current forums you have on your site: If you hover over a forum, two options will appear: Edit, which will allow you to edit the forum. A screen similar to the New Forum page will appear, which will allow you to make changes to your forum. The second option is Trash, which will move your forum into Trash. After a while, it will be deleted from your site. When you click on Trash, you will trash everything associated with your forum (any topics, replies, or tags will be deleted). Be careful! Summary Right now, you should have a bustling forum, ably overseen by yourself and maybe even a couple of Moderators.Remember that all I have described so far has been how to use bbPress to manage your forum, and not how to manage your forum. Each forum will have its own rules and guidelines, and you will eventually learn how to manage your bbPress forum with more and more members joining in.A general rule of thumb, though, is set out your rules at the start of your forum, welcome change, act quickly on violations, and most importantly, treat your users with respect. As without users, you will have a very quiet forum. However, bbPress is a WordPress plugin, and in itself can be extensible and can take advantage of plugins and themes, both specifically designed for bbPress or even those that work with WordPress. Resources for Article: Further resources on this subject: Getting Started with WordPress 3 [Article] How to Create an Image Gallery in WordPress 3 [Article] Integrating phpList 2 with WordPress [Article]
Read more
  • 0
  • 0
  • 2629

article-image-installing-magento
Packt
19 Aug 2013
22 min read
Save for later

Installing Magento

Packt
19 Aug 2013
22 min read
(For more resources related to this topic, see here.) Installing Magento locally Whether you're working on a Windows computer, Mac, or Linux machine, you will notice very soon that it comes in handy to have a local Magento test environment available. Magento is a complex system and besides doing regular tasks, such as adding products and other content, you should never apply changes to your store directly in the live environment. When you're working on your own a local test system is easy to set up and it gives you the possibility to test changes without any risk. When you're working in a team it makes sense to have a test environment running on your own server or hosting provider. In here, we'll start by explaining how to set up your local test system. Requirements Before we jump into action, it's good to have a closer look at Magento's requirements. What do you need to run it? Simply put, all up-to-date requirements for Magento can be found here: http://www.magentocommerce.com/system-requirements. But maybe that's a bit overwhelming if you are just a beginner. So let's break this up into the most essential stuff: Requirement Notes Operating system: Linux Magento runs best on Linux, as offered by most hosting companies. Don't worry about your local test environment as that will run on Windows or Mac as well. But for your live store you should go in for a Linux solution because if you decide to run it on anything else other than Linux for a live store, it will not be supported. Web server: Apache Magento runs on Versions 1.3.x, 2.0.x, and 2.2.x of this very popular web server. As of Version 1.7 of Magento community and Version 1.12 of Magento Enterprise there's a new web server called Nginx that is compatible as well. Programming language: PHP Magento has been developed using PHP, a programming language which is very popular. Many major open source solutions such as WordPress and Joomla for instance, have been built using PHP. Use Versions 5.2.13 - 5.3.15. Do not use PHP4 anymore, nor use PHP 5.4 yet! PHP extensions Magento requires a number of extensions, which should be available on top of PHP itself. You will need: PDO_MySQL, mcrypt, hash, simplexml, GD, DOM, Iconv, and Curl. Besides that you also need to have the possibility to switch off ''safe mode''. You do not have a clue about all of this? Don't worry. A host offering Magento services already takes care of this. And for your local environment there are only a few additional steps to take. We'll get there in a minute. Database: MySQL MySQL is the database, where Magento will store all data for your store. Use Version 4.1.20 or (and preferably) newer. As you can see, even in a simplified format, there are quite some things that need to be taken care of. Magento hosting is not as simple as hosting for a small WordPress or Joomla! website, currently the most popular open source solutions to create a regular site. The requirements are higher and you just cannot expect to host your store for only a couple of dollars per month. If you do, your online store may still work, but it is likely that you'll run into some performance issues. Be careful with the cheapest hosting solutions. Although Magento may work, you'll be consuming too that need server resources soon. Go for a dedicated server or a managed VPS (Virtual Private Server), but definitely for a host that is advertising support of Magento. Time for action – installing Magento on a Windows machine We'll speak more deeply about Magento hosting later on. Let's first download and install the package on a local Windows machine. Are you a Mac user? Don't worry, we'll give instructions for Mac users as well later on. Note that the following instructions are written for Windows users, but will contain valuable information for Mac users as well. Perform the following steps to install Magento on your Windows computer: Download the Magento installation package. Head over to http://www.magentocommerce.com/download and download the package you need. For a Windows user almost always the full ZIP package is the most convenient one. In our situation Version 1.7.0.2 is the latest one, but please be aware that this will certainly change over time when newer versions are released. You will need to create a (free) account to download the software. This account will also be helpful later on. It will give you access to the Magento support forums, so make sure to store your login details somewhere.The download screen should look something like this: If you're a beginner then it is handy to have some sample data in your store. Magento offers a download package containing sample data on the same page, so download that as well. Note that for a production environment you would never install the sample data, but for a test system like the local installation we're doing here, it might be a good idea to use it. The sample data will create a few items and customers in your store, which will make the learning process easier. Did you notice the links to Magento Go at every download link? Magento Go is Magento's online platform, which you can use out of the box, without doing any installation at all. However, in the remaining part of this article, we assume that you are going to set up your own environment and want to have full control over your store. Next, you need a web server, so that you can run your website locally, on your own machine. On Windows machines, XAMPP is an easy to use all-in-one solution. Download the installer version via: http://www.apachefriends.org/en/xampp-windows.html. XAMPP is also available for Mac and Linux. The download screen is as follows: Once downloaded, run the executable code to start the installation process. You might receive some security warnings that you have to accept, especially when you're using Windows Vista, 7 or 8, like in the following example: Because of this it's best to install XAMPP directly in the root of your hard drive, c:xampp in most cases. Once you click on OK, you will see the following screen, which shows the progress of installation: Once the installation has finished, the software asks if you'd like to start the Control Panel. If you do so, you'll see a number of services that have not been started yet. The minimum that you should start by clicking the Start button are Apache, the web server and MySQL, the database server. Now you're running your own web server on your local computer. Be aware that generally this web server will not be accessible for the outside world. It's running on your local machine, just for testing purposes. Before doing the next step, please verify if your web server is actually running. You can do so by using your browser and going to http://localhost or http://127.0.0.1 If all went well you should see something similar to the following: No result? If you're on a Windows computer, please first reboot your machine. Next, check using the XAMPP control panel if the Apache service is running. If it isn't, try to start it and pay attention to the error messages that appear. Need more help? Start with the help available on XAMPP's website at: http://www.apachefriends.org/en/faq-xampp-windows.html. Can't start the Apache service? Check if there are any other applications using ports 80 and 443. The XAMPP control panel will give you more information. One of the applications that you should for instance stop before starting XAMPP is Skype. It's also possible to change this setting in Skype by navigating to Tools | Options | Advanced | Connections. Change the port number to something else, for instance port 8080. Then close and restart Skype. This prevents the two from interfering with each other in the future. So, the next thing that needs to be done is installing Magento on top of it. But before we do so, we first have to change a few settings. Change the following Windows file: C:WindowsSystem32driversetchosts.Make sure to open your editor using administrator rights, otherwise you will not be able to save your changes. Add the following line to the host file: 127.0.0.1 www.localhost.com. This is needed because Magento will not work correctly on a localhost without this setting. You may use a different name, but the general rule is that at least one dot must be used in the local domain name. The following screenshot gives an example of a possible host file. Please note that every host file will look a bit different. Also, your security software or Windows security settings may prevent you from making changes to this file, so please make sure you have the appropriate rights to change and save its contents: Do you need a text editor? There are really lots of possibilities when it comes to editing text for the web, as long as you use a ''plain text'' editor. Something like Microsoft Word isn't suitable because it will add a lot of unwanted code to your files! For very simple things like the one above, even Notepad would work. But soon you'll notice that it is much more convenient to use an editor that will help you in structuring and formatting your files. Personally, I can recommend the free Notepad++ for Windows users, which is even available in lots of different languages: http://notepad-plus-plus.org. Mac users can have a look at Coda: http://panic.com/coda/ or TextWrangler http://www.barebones.com/products/textwrangler/. Unzip the downloaded Magento package and put all files in a subfolder of your XAMPP installation. This could for instance be c:xampphtdocsmagento. Now, go to www.localhost.com/magento to check if the installation screen of Magento is visible, as shown in the following screenshot. But do not yet start the installation process! Before you start the installation, first create a MySQL database. To do this, use a second browser tab and navigate to localhost | phpMyAdmin. By default the user is root, and so without a password you should be able to continue without logging in. Click on Databases and create a database with a name of your choice. Write it down, as you will need it during the Magento installation. After creating the database you may close the browser tab. It's finally time to start the installation process now. Go back to the installation screen of Magento, accept the license agreement and click on Continue. Next, set your country, Time Zone and Default Currency. If you're working with multiple currencies that will be addressed later on: The next screen is actually the most important one of the installation process and this is where most beginners go wrong because they do not know what values to use. Using XAMPP this is an easy task, however, fill in your Database Name, User Name (root) and do not forget to check the Skip Base URL Validation Before the Next Step box, otherwise your installation might fail: In this same form there are some fields that you can use to immediately improve the security level of your Magento setup. On a local test environment that isn't necessary, so we'll pay attention to those settings later on when we'll discuss installing Magento at a hosting provider. Please note that the Use Secure URLs option should remain unchecked for a local installation like we're doing here. In the last step, yes, really! Just fill out your personal data and chose a username and password. Also in here, since you're working locally you do not have to create a complicated, unique password now. But you know what we mean, right? Doing a live installation at a hosting provider requires a good, strong password! You do not have to fill the Encryption Key field, Magento will do that for you: In the final screen please just make a note of the Encryption Key value that was generated. You might need it in the future whenever upgrading your Magento store to a newer software version: What just happened? Congratulations! You just installed Magento for the very first time! Summarizing it, you just: Downloaded and installed XAMPP Changed your Windows host file Created a MySQL database using PhpMyAdmin Installed Magento I'm on Mac; what should I do? Basically, the steps using XAMPP are a bit different if you're using Mac. We shall be using Mac OS X 10.8 as an example of Mac OS version. According to our experience, as an alternative to XAMPP, MAMP is a bit easier if you are working with Mac. You can find the MAMP software here: http://www.mamp.info/en/downloads/index.html And the documentation for MAMP is available here: http://documentation.mamp.info/en/mamp/installation The good thing about MAMP is that it is easy to install, with very few configuration changes. It will not conflict with any already running Apache installation on your Mac, in case you have any. And it's easy to delete as well; just removing the Mamp folder from your Applications folder is already sufficient to delete MAMP and all local websites running on it. Once you've downloaded the package, it will be in the Downloads folder of your Mac. If you are running Mac OS X 10.8, you first need to set the correct security settings to install MAMP. You can find out which version of Mac OS X you have using the menu option in the top-left corner of your screen: You can find the security settings menu by again going to the Apple menu and then selecting System Preferences: In System Preferences, select the Security & Privacy icon that can be found in the first row as seen in the following screenshot: In here, press the padlock and enter your admin password. Next, select the Anywhere radio button in the Allow applications downloaded from: section. This is necessary because it will not be possible to run the MAMP installation you downloaded without it: Open the image you've downloaded and simply move the Mamp folder to your Applications folder. That's all. Now that you've MAMP installed on your system, you may launch MAMP.app (located at Applications | Mamp | Mamp.app). While you're editing your MAMP settings, MAMP might prompt you for an administrator password. This is required because it needs to run two processes: httpd (Apache) and mysqld (MySQL). Depending on the settings you set for those processes, you may or may not need to enter your password. Once you open MAMP, click on Preferences button. Next, click on Ports. The default MAMP ports are 8888 for Apache, and 8889 for MySQL. If you use this configuration, you will not be asked for your password, but you will need to include the port number in the URL when using it (http://localhost:8888). You may change this by setting the Apache port to 80, for which you'll probably have to enter your administrator password. If you have placed your Magento installation in the Shop folder, it is advised to call your Magento installation through the following URL: http://127.0.0.1:8888/shop/, instead of http://localhost:8888/shop/. The reason for this is that Magento may require dots in the URL. The last thing you need to do is visit the Apache tab, where you'll need to set a document root. This is where all of your files are going to be stored for your local web server. An example of a document root is Users | Username | Sites. To start the Apache and MySQL servers, simply click on Start Servers from the main MAMP screen. After the MAMP servers start, the MAMP start page should open in your web browser. If it doesn't, click on Open start page in the MAMP window. From there please select phpMyAdmin. In PhpMyAdmin, you can create a database and start the Magento installation procedure, just like we did when installing Magento on a Windows machine. See the Time for action – installing Magento on a Windows machine section, point 8 to continue the installation of Magento. Of course you need to put the Magento files in your Mamp folder now, instead of the Windows path mentioned in that procedure. In some cases, it is necessary to change the Read & Write permissions of your Magento folder before you can use Magento on Mac. To do that, right-click on the Magento folder, and select the Get Info option. In the bottom of the resulting screen, you will see the folder permissions. Set all of these to Read & Write, if you have trouble in running Magento. Installing Magento at a hosting service There are thousands of hosting providers with as many different hosting setups. The difficulty of explaining the installation of Magento at a commonly used hosting service is that the procedure differs from hosting provider to hosting provider, depending on the tools they use for their services. There are providers, for instance, who use Plesk, DirectAdmin, or cPanel. Although these user environments differ from each other, the basic steps always remain the same: Check the requirements of Magento (there's more information on this topic at the beginning of this article). Upload the Magento installation files using an ftp tool, for instance, Filezilla (download this free at: http://filezilla-project.org). Create a database. This step differs slightly per hosting provider, but often a tool, such as PhpMyAdmin is used. Ask your hosting provider if you're in doubt about this step. You will need: the database name, database user, password, and the name of the database server. Browse to your domain and run the Magento installation process, which is the same as we saw earlier in this article. How to choose a Magento hosting provider One important thing we didn't discuss yet during this article is selecting a hosting provider that is capable of running your online store. We already mentioned that you should not expect performance for a couple of dollars per month. Magento will often still run at a cheap hosting service, but the performance is regularly very poor. So, you should pay attention to your choices here and make sure you make the right decision. Of course everything depends on the expectations for your online store. You should not aim for a top performance, if all you expect to do during your first few years is 10,000 dollars of revenue per year. OK, that's difficult sometimes. It's not always possible to create a detailed estimation of the revenue you may expect. So, let's see what you should pay attention to: Does the hosting provider mention Magento on its website? Or maybe they are even offering special Magento hosting packages? If yes, you are sure that technically Magento will run. There are even hosting providers for which Magento hosting is their speciality. Are you serious about your future Magento store? Then ask for references! Clients already running on Magento at this hosting provider can tell you more about the performance and customer support levels. Sometimes a hosting provider also offers an optimized demo store, which you can check out to see how it is performing. Ask if the hosting provider has Magento experts working for them and if yes, how many. Especially in case of large, high-traffic stores, it is important to hire the knowledge you need. Do not forget to check online forums and just do some research about this provider. However, we must also admit that you will find negative experiences of customers about almost every hosting provider. Are you just searching for a hosting provider to play around with Magento? In that case any cheap hosting provider would do, although your Magento store could be very slow. Take for instance, Hostgator (http://hostgator.com), which offers small hosting plans for a couple of U.S. dollars per month. Anyway, a lot of hosts are offering a free trial period, which you may use to test the performance. Installatron Can't this all be done a bit more easily? Yes, that's possible. If your host offers a service named Installatron and if it also includes Magento within it, your installation process will become a lot easier. We could almost call it a ''one-click'' installation procedure. Check if your hosting provider is offering the latest Magento version; this may not always be the case! Of course you may ask your (future) hosting provider if they are offering Installatron on their hosting packages. The example shown is from Simple Helix provider (http://simplehelix.com), a well-known provider specialized in Magento hosting solutions. Time for action – installing Magento using Installatron The following short procedure shows the steps you need to take to install Magento using Installatron: First, locate the Installatron Applications Installer icon in the administration panel of your hosting provider. Normally this is very easy to find, just after logging in: Next, within Installatron Applications Installer, click on the Applications Browser option: Inside Applications Browser, you'll see a list of CMS solutions and webshop software that you can install. Generally Magento can be located in the e-Commerce and Business group: Of course, click on Magento and after that click on the Install this application button. The next screen is the setup wizard for installing Magento. It lists a bunch of default settings, such as admin username, database settings, and the like. We recommend to change as little as possible for your first installation. You should pick the right location to install though! In our example, we will choose the test directory on www.boostingecommerce.com: Note that for this installation, we've chosen to install the Magento sample data, which will help us in getting an explanation of the Magento software. It's fine if you're installing for learning purposes, but in a store that is meant to be your live shop, it's better to start off completely empty. In the second part of the installation form, there are a few fields that you have to pay attention to: Switch off automatic updates Set database management to automatic Choose a secure administrator password Click on the Install button when you are done reviewing the form. Installatron will now begin installing Magento. You will receive an e-mail when Installatron is ready. It contains information about the URL you just installed and your login credentials to your newfangled Magento shop. That's all! Our just installed test environment is available at http://www.boostingecommerce.com/test. If all is well, yours should look similar to the following screenshot: How to test the minimum requirements If your host isn't offering Installatron and you would like to install Magento on it, how will you know if it's possible? In other words, will Magento run? Of course you can simply try to install and run Magento, but it's better to check for the minimum requirements before going that route. You can use the following method to test if your hosting provider meets all requirements needed to run Magento. First, create a text file using your favorite editor and name it as phpinfo.php. The contents of the file should be: <?php phpinfo(); ?> Save and upload this file to the root folder of your hosting environment, using an ftp tool such as Filezilla. Next, open your browser using this address: http://yourdomain.com/phpinfo.php; use your own domain name of course. You will see a screen similar to the following: Note that in the preceding screenshot, our XAMPP installation is using PHP 5.4.7. And as we mentioned earlier, Magento isn't compatible with this PHP version yet. So what about that? Well, XAMPP just comes with a recent stable release of PHP. Although it is officially not supported, in most cases your Magento test environment will run fine. Something similar to the previous screenshot will be shown, depending on your PHP (and XAMPP) version. Using this result, we can check for any PHP module that is missing. Just go through the list at the beginning of this article and verify if everything that is needed is available and enabled: What is SSL and do I need it? SSL (Secure Sockets Layer) is the standard for secure transactions on the web. You'll recognize it by websites running on https:// instead of http://. To use it, you need to buy an SSL Certificate and add it to your hosting environment. Some hosting providers offer it as a service, whereas others just point to third parties offering SSL Certificates, like for instance, RapidSSL (https://www.rapidssl.com) or VeriSign (http://www.verisign.com), currently owned by Symantec. We'll not offer a complete set of instructions on using SSL here, which is beyond the scope of this article. However, it is good to know when you'll need to pay attention to SSL. There can be two reasons to use an SSL certificate: You are accepting payments directly on your website and may even be storing credit card information. In such a case, make sure that you are securing your store by using SSL. On the other hand, if you are only using third parties to accept payments, like for example, Google Checkout or PayPal, you do not have to worry about this part. The transaction is done at the (secure part of the) website of your payment service provider and in such a case you do not need to offer SSL. However, there's another reason that makes using SSL interesting for all shop owners: trust. Regular shoppers know that https:// connections are secure and might feel just a bit more comfortable in closing the sale with you. It might seem a little thing, but getting a new customer to trust you is an essential step of the online purchase process. Summary In this article we've gone through several different ways to install Magento. We looked at doing it locally on your own machine using XAMPP or MAMP, or by using a hosting provider to bring your store online. When working with a hosting provider, using the Installatron tool makes the Magento installation very easy. Resources for Article: Further resources on this subject: Magento: Exploring Themes [Article] Getting Started with Magento Development [Article] Integrating Facebook with Magento [Article]
Read more
  • 0
  • 0
  • 3850

article-image-building-ui-xaml-windows-8-using-c
Packt
16 Aug 2013
35 min read
Save for later

Building UI with XAML for Windows 8 Using C

Packt
16 Aug 2013
35 min read
(For more resources related to this topic, see here.) XAML C++ Store applications typically use eXtensible Application Markup Language (XAML) as the main language for creating the user interface. The first question that comes to mind when XAML is first mentioned, is why? What's wrong with C++, or any other existing programming language? XAML is an XML-based language that describes the what, not the how; it's declarative and neutral. Technically, a complete app can be written without any XAML; there's nothing XAML can do that C++ can't. Here are some reasons why XAML makes sense (or at least may make sense in a little bit): C++ is very verbose as opposed to XAML. XAML is usually shorter than the equivalent C++ code. Since XAML is neutral, design-oriented tools can read and manipulate it. Microsoft provides the Expression Blend tool just for this purpose. The declarative nature of XAML makes it easier (most of the time, after users get used to it) to build user interfaces, as these have a tree-like structure, just like XML. XAML itself has nothing to do with the user interface in itself. XAML is a way to create objects (usually an object tree) and set their properties. This works for any type that is "XAML friendly", meaning it should have the following: A default public constructor Settable public properties The second point is not a strict requirement, but without properties the object is pretty dull. XAML was originally created for Windows Presentation Foundation (WPF), the main rich client technology in .NET. It's now leveraged in other technologies, mostly in the .NET space, such as Silverlight and Windows Workflow Foundation (WF). The XAML level currently implemented in WinRT is roughly equivalent to Silverlight 3 XAML. In particular, it's not as powerful as WPF's XAML. XAML basics XAML has a few rules. Once we understand those rules, we can read and write any XAML. The most fundamental XAML rules are as follows: An XML element means object creation An XML attribute means setting a property (or an event handler) With these two rules, the following markup means creating a Button object and setting its Content property to the string Click me: <Button Content="Click me!" /> The equivalent C++ code would be as follows: auto b = ref new Button;b->Content = "Click me"; When creating a new Blank App project, a MainPage.xaml file is created along with the header and implementation files. Here's how that XAML file looks: <Pagex:Class="BasicXaml.MainPage"mc:Ignorable="d"><Grid Background="{StaticResourceApplicationPageBackgroundThemeBrush}"></Grid></Page> It's worth going over these lines in detail. In this example, the project name is BasicXaml. The root element is Page and an x:Class attribute is set, indicating the class that inherits from Page, here named BasicXaml::MainPage. Note that the class name is the full name including namespace, where the separator must be a period (not the C++ scope resolution operator ::). x:Class can only be placed on the root element. What follows that root element is a bunch of XML namespace declarations. These give context to the elements used in the entire XAML of this page. The default XML namespace (without a name) indicates to the XAML parser that types such as Page, Button, and Grid can be written as they are, without any special prefix. This is the most common scenario, because most of the XAML in a page constitutes user interface elements. The next XML namespace prefix is x and it points to special instructions for the XAML parser. We have just seen x:Classin action. We'll meet other such attributes later in this article. Next up is a prefix named local, which points to the types declared in the BasicXaml namespace. This allows creating our own objects in XAML; the prefix of such types must be local so that the XAML parser understands where to look for such a type (of course, we can change that to anything we like). For example, suppose we create a user control derived type named MyControl. To create a MyControl instance in XAML, we could use the following markup: <local:MyControl /> The d prefix is used for designer-related attributes, mostly useful with Expression Blend. The mc:ignorable attribute states that the d prefix should be ignored by the XAML parser (because it's related to the way Blend works with the XAML). The Grid element is hosted inside the Page, where "hosted" will become clear in a moment. Its Background property is set to {StaticResource ApplicationPageBackgroundThemeBrush}. This is a markup extension, discussed in a later section in this article. XAML is unable to invoke methods directly; it can just set properties. This is understandable, as XAML needs to remain declarative in nature; it's not meant as a replacement for C++ or any other programming language. Type converters XML deals with strings. However, it's clear that many properties are not strings. Many can still be specified as strings, and still work correctly thanks to the type converters employed by the XAML parser. Here's an example of a Rectangle element: <Rectangle Fill="Red" /> Presumably, the Fill property is not of a string type. In fact, it's a Brush. Red here really means ref new SolidColorBrush(Colors::Red). The XAML parser knows how to translate a string, such as Red (and many others) to a Brush type (in this case the more specific SolidColorBrush). Type converters are just one aspect of XAML that make it more succinct than the equivalent C++ code. Complex properties As we've seen, setting properties is done via XML attributes. What about complex properties that cannot be expressed as a string and don't have type converters? In this case, an extended syntax (property element syntax) is used to set the property. Here's an example: <Rectangle Fill="Red"><Rectangle.RenderTransform><RotateTransform Angle="45" /></Rectangle.RenderTransform></Rectangle> Setting the RenderTransform property cannot be done with a simple string; it must be an object that is derived from the Transform class (RotateTransform in this case). The preceding markup is equivalent to the following C++ code: auto r = ref new Rectangle;r->Fill = ref new SolidColorBrush(Colors::Red);auto rotate = ref new RotateTransform();rotate->Angle = 45;r->RenderTransform = rotate; Dependency properties and attached properties Most propertieson various elements and controls are not normal, in the sense that they are not simple wrappers around private fields. It's important to realize that there is no difference in XAML between a dependency property and a regular property; the syntax is the same. In fact, there is no way to tell if a certain property is a dependency property or not, just by looking at its use in XAML. Dependency properties provide the following features Change notifications when the property value changes Visual inheritance for certain properties (mostly the font-related properties) Multiple providers that may affect the final value (one wins out) Memory conservation (value not allocated unless changed) Some WinRT features, such as data binding, styles, and animations are dependent on that support. Another kind of dependency properties is attached properties. But essentially an attached property is contextual—it's defined by one type, but can be used by any type that inherits from DependencyObject (as all elements and controls do). Since this kind of property is not defined by the object it's used on,it merits a special syntax in XAML. The following is an example of a Canvaspanel that holds two elements: <Canvas><Rectangle Fill="Red" Canvas.Left="120" Canvas.Top="40"Width="100" Height="50"/><Ellipse Fill="Blue" Canvas.Left="30" Canvas.Top="90"Width="80" Height="80" /></Canvas> The Canvas.Left and Canvas.Top are attached properties. They were defined by the Canvas class, but they are attached to the Rectangle and Ellipse elements. Attached properties only have meaning in certain scenarios. In this case, they indicate the exact position of the elements within the canvas .The canvas is the one that looks for these properties in the layout phase.This means that if those same elements were placed in, say a Grid, those properties would have no effect, because there is no interested entity in those properties (there is no harm in having them, however). Attached properties can be thought of as dynamic properties that may or may not be set on objects. This is the resulting UI: Setting an attached property in code is a little verbose. Here's the equivalent C++ code for setting the Canvas.Left and Canvas.Top properties on an element named _myrect: Canvas::SetLeft(_myrect, 120);Canvas::SetTop(_myrect, 40); Content properties The relationship between a Page object and a Grid object is not obvious. Grid seems to be inside the Page. But how would that translate to code? The Page/Grid markup can be summed up as follows (ignoring the detailed markup): <Page><Grid Background="..."></Grid></Page> This is actually a shortcut for the following markup: <Page><Page.Content><Grid Background="..."></Grid></Page.Content></Page> This means the Grid object is set as the Content property of the Page object; now the relationship is clear. The XAML parser considers certain properties (no more than one per type hierarchy) as the default or content properties. It doesn't have to be named Content, but it is in the Page case. This attribute is specified in the control's metadata using the Windows::UI::Xaml::Markup::ContentAttribute class attribute. Looking at the Visual Studio object browser for the Page class shows no such attribute. But Page inherits from UserControl; navigating to UserControl, we can see the attribute set: Attributes are a way to extend the metadata for a type declaratively. They can be inserted in C++/CX by an attribute type name in square brackets before the item that attribute is applied to (can be a class, interface, method, property, and other code element). An attribute class must derive from Platform::Metadata::Attribute to be considered as such by the compiler. Some of the common ContentProperty properties in WinRT types are as follows: Content of ContentControl (and all derived types) Content of UserControl Children of Panel (base class for all layout containers) Items of ItemsControl (base class for collection-based controls) GradientStops of GradientBrush (base class of LinearGradientBrush) Collection properties Some properties are collections (of type IVector<T> or IMap<K,V>, for instance).Such properties can be filled with objects, and the XAML parser will call the IVector<T>::Append or IMap<K,V>::Insert methods. Here's an example for a LinearGradientBrush: <Rectangle><Rectangle.Fill><LinearGradientBrush EndPoint="1,0"><GradientStop Offset="0" Color="Red" /><GradientStop Offset=".5" Color="Yellow" /><GradientStop Offset="1" Color="Blue" /></LinearGradientBrush></Rectangle.Fill></Rectangle> Two rules are at work here. The first is the ContentProperty of LinearGradientBrush (GradientStops), which need not be specified. It's of the type GradientStopCollection, which implements IVector<GradientStop>, and thus is eligible for automatic appending. This is equivalent to the following code: auto r = ref new Rectangle;auto brush = ref new LinearGradientBrush;brush->EndPoint = Point(1.0, 0);auto stop = ref new GradientStop;stop->Offset = 0; stop->Color = Colors::Red;brush->GradientStops->Append(stop);stop = ref new GradientStop;stop->Offset = 0.5; stop->Color = Colors::Yellow;brush->GradientStops->Append(stop);stop = ref new GradientStop;stop->Offset = 1; stop->Color = Colors::Blue;brush->GradientStops->Append(stop);r->Fill = brush; This is perhaps the first clear sign of XAML syntax advantage over C++. Here's the rectangle in all its glory: In the case of IMap<K,V>, an attribute named x:Key must be set on each item to indicate the key sent to the IMap<K,V>::Insert method. We'll see an example of such a map later in this article, when we will discuss resources. Markup extensions Markup extensions are special instructions to the XAML parser that provide ways of expressing things that are beyond object creation or setting some property. These instructions are still declarative in nature, but their code equivalent usually entails calling methods, which is not directly possible in XAML. Markup extensions are placed inside curly braces as property values. They may contain arguments and properties, as we'll see in later chapters. The only markup extension used by default in a blank page is {StaticResource}, which will be discussed later in this article. WPF and Silverlight 5 allow developers to create custom markup extensions by deriving classes from MarkupExtension. This capability is unavailable in the current WinRT implementation. One simple example of a markup extension is {x:Null}. This is used in XAML whenever the value nullptr needs to be specified, as there's no better way to use a string for this. The following example makes a hole in the Rectangle element: <Rectangle Stroke="Red" StrokeThickness="10" Fill="{x:Null}" /> Naming elements Objects created through XAML can be named using the x:Name XAML attribute. Here's an example: <Rectangle x_Name="r1">…</Rectangle> The net result is a private member variable (field) that is created by the XAML compiler inside MainPage.g.h (if working on MainPage.xaml): private: ::Windows::UI::Xaml::Shapes::Rectangle^ r1; The reference in itself must be set in the implementation of MainPage::InitializeComponent with the following code: // Get the Rectangle named 'r1'r1 = safe_cast<::Windows::UI::Xaml::Shapes::Rectangle^>(static_cast<Windows::UI::Xaml::IFrameworkElement^>(this)->FindName(L"r1")); The mentioned file and method are discussed further in the section XAML compilation and execution. Regardless of how it works, r1 is now a reference to that particular rectangle. Connecting events to handlers Events can be connected to handlers by using the same syntax as setting properties, but in this case the value of the property must be a method in the code behind class with the correct delegate signature. Visual Studio helps out by adding a method automatically if Tab is pressed twice after entering the event name (in the header and implementation files). The default name that Visual Studio uses includes the element's name (x:Name) if it has one, or its type if it doesn't, followed by an underscore and the event name, and optionally followed by an underscore and an index if duplication is detected. The default name is usually not desirable; a better approach that still has Visual Studio creating the correct prototype is to write the handler name as we want it, and then right-click on the handler name and select Navigate to Event Handler. This has the effect of creating the handler (if it does not exist) and switching to the method implementation. Here's an example of an XAML event connection: <Button Content="Change" Click="OnChange" /> And the handler would be as follows (assuming the XAML is in MainPage.xaml): void MainPage::OnChange(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e){} Visual Studio also writes the namespace name in front of the class name (deleted in the preceding code example); this can be deleted safely, since an in-use namespace statement exists at the top of the file for the correct namespace. Also, the usage of Platform::Object instead of just Object (and similarly for RoutedEventArgs) is less readable; the namespace prefixes can be removed, as they are set up at the top of the file by default. All events (by convention) use delegates that are similar. The first argument is always the sender of the event (in this case a Button) and the second parameter is the extra information regarding the event. RoutedEventArgs is the minimum type for events, known as routed events. A detailed discussion of routed events is covered in the next article. XAML rules summary This is a summary of all XAML rules: An XAML element means creating an instance. An XAML attribute sets a property or an event handler. For properties, a type converter may execute depending on the property's type. Complex properties are set with the Type.Property element syntax. Attached properties are set with the Type.Property syntax, where Type is the declaring type of the attached property. ContentPropertyAttribute sets a Content property that need not be specified. Properties that are collections cause the XAML parser to call Append or Insert, as appropriate, automatically. Markup extensions allow for special (predefined) instructions. Introducing the Blend for Visual Studio 2012 tool Visual Studio 2012 is installed with the Blend for Visual Studio 2012 tool. This tool is typically used by UI designers to create or manipulate the user interface for XAML-based applications. The initial release of Blend for Visual Studio 2012 only supported Windows 8 Store Apps and Windows Phone 8 projects. The support for WPF 4.5 and Silverlight was added in Update 2 for Visual Studio 2012. Blend can be used alongside Visual Studio 2012, as both understand the same file types (such as solution .sln files). It's not atypical to switch back and forth between the two tools—using each tool for its strengths. Here's a screenshot of Blend with the CH03.sln solution file open (the solution that holds all the samples for this article): The preceding screenshot shows a particular XAML file open, with one button selected. Several windows comprise Blend, some of which are similar to their Visual Studio counterparts, namely Projects and Properties. Some of the new windows include: Assets: Holds the elements and controls available in WinRT (along with some other useful shortcuts) Objects and Timeline: Include all objects in the visual tree and also animations Resources: Holds all resources (refer to the next section) within the application Blend's design surface allows manipulating elements and controls, which is also possible to do in Visual Studio. Blend's layout and some special editing features make it easier for UI/graphic designers to work with as it mimics other popular applications, such as Adobe Photoshop and Illustrator. Any changes made using the designer are immediately reflected by the changed XAML. Switching back to Visual Studio and accepting the reload option synchronizes the files; naturally, this can be done both ways. It's possible to work from within Blend entirely. Pressing F5 builds and launches the app in the usual way. Blend, however, is not Visual Studio, and breakpoints and other debugging tasks are not supported. Blend is a non-trivial tool, and is well beyond the scope of this book. Experimentation can go a long way, however. XAML compilation and execution The XAML compiler that runs as part of the normal compilation process, places the XAML as an internal resource within the EXE or DLL. In the constructor of a XAML root element type (such as MainPage), a call is made to InitializeComponent. This method uses a static helper method Application::LoadComponent to load the XAML and parse it—creating objects, setting properties, and so on. Here's the implementation created by the compiler for InitializeComponent (in MainPage.g.hpp, with some code cleaning): void MainPage::InitializeComponent() {if (_contentLoaded)return;_contentLoaded = true;// Call LoadComponent on ms-appx:///MainPage.xamlApplication::LoadComponent(this,ref new ::Windows::Foundation::Uri(L"ms-appx:///MainPage.xaml"),ComponentResourceLocation::Application);} Connecting XAML, H, and CPP files to the build process From a developer's perspective, working with a XAML file carries with it two other files, the H and CPP. Let's examine them in a little more detail. Here's the default MainPage.xaml.h (comments and namespaces removed): #include "MainPage.g.h"namespace BasicXaml {public ref class MainPage sealed {public:MainPage();protected:virtual void OnNavigatedTo(NavigationEventArgs^ e)override;};} The code shows a constructor and a virtual method override named OnNavigatedTo (unimportant for this discussion). One thing that seems to be missing is the InitializeComponent method declaration mentioned in the previous section. Also the inheritance from Page that was hinted at earlier is missing. It turns out that the XAML compiler generates another header file named MainPage.g.h (g stands for generated) based on the XAML itself (this is evident with the top #include declaration). This file contains the following (it can be opened easily by selecting the Project | Show All Files, or the equivalent toolbar button, or right clicking on #include and selecting Open Document…): namespace BasicXaml {partial ref class MainPage : public Page,public IComponentConnector {public:void InitializeComponent();virtual void Connect(int connectionId, Object^ target);private:bool _contentLoaded;};} Here we find the missing pieces. Here we find InitializeComponent, as well as the derivation from Page. How can there be more than one header file per class? A new C++/CX feature called partial classes allows this. The MainPage class is marked as partial, meaning there are more parts to it. The last part should not be marked as partial, and should include at least one header so that a chain forms, eventually including all the partial headers; all these headers must be part of the same compilation unit (a CPP file). This MainPage.g.h file is generated before any compilation happens; it's generated on the fly while editing the XAML file. This is important because named elements are declared in that file, providing instance intellisense. During the compilation process, MainPage.cpp is finally compiled, producing an object file, MainPage.obj. It still has some unresolved functions, such as InitializeComponent. At this time, MainPage.obj (along with other XAML object files, if exist) is used to generate the metadata (.winmd) file. To complete the build process, the compiler generates MainPage.g.hpp, which is actually an implementation file, created based on the information extracted from the metadata file (the InitializeComponentimplementation is generated in this file). This generated file is included just once in a file called XamlTypeInfo.g.cpp, which is also generated automatically based on the metadata file, but that's good enough so that MainPage.g.hppis finally compiled, allowing linking to occur correctly. Resources The term "resources" is highly overloaded. In classic Win32 programming, resources refer to read-only chunks of data, used by an application. Typical Win32 resources are strings, bitmaps, menus, toolbars, and dialogs, but custom resources can be created as well, making Win32 treat those as unknown chunks of binary data. WinRT defines binary, string, and logical resources. The following sections discuss binary and logical resources (string resources are useful for localization scenarios and will not be discussed in this section). Binary resources Binary resources refer to chunks of data, provided as part of the application's package. These typically include images, fonts, and any other static data needed for the application to function correctly. Binary resources can be added to a project by right-clicking on the project in Solution Explorer, and selecting Add Existing Item. Then, select a file that must be in the project's directory or in a subdirectory. Contrary to C# or VB projects, adding an existing item from a location does not copy the file to the project's directory. This inconsistency is a bit annoying for those familiar with C#/VB projects, and hopefully will be reconciled in a future Visual Studio version or service pack. A typical Store app project already has some binary resources stored in the Assets project folder, namely images used by the application: Using folders is a good way to organize resources by type or usage. Right-clicking on the project node and selecting Add New Filter creates a logical folder, to which items may be dragged. Again, contrary to C#/VB projects, project folders are not created in the filesystem. It's recommended that these are actually created in the filesystem for better organization. The added binary resource is packaged as part of the application's package and is available in the executable folder or subfolder, keeping its relative location. Rightclicking on such a resource and selecting Properties yields the following dialog: The Content attribute must be set to Yes for the resource to be actually available (the default). Item Type is typically recognized by Visual Studio automatically. In case, it doesn't, we can always set it to Text and do whatever we want with it in code. Don't set Item Type to Resource. This is unsupported in WinRT and will cause compile errors (this setting is really for WPF/Silverlight). Binary resources can be accessed in XAML or in code, depending on the need. Here's an example of using an image named apple.png stored in a subfolder in the application named Images under the Assets folder by an Image element: <Image Source="/Assets/Images/apple.png" /> Note the relative URI. The preceding markup works because of a type converter that's used or the Image::Source property (which is of the type ImageSource). That path is really a shortcut for the following, equivalent, URI: <Image Source="ms-appx:///Assets/Images/apple.png" /> Other properties may require a slightly different syntax, but all originate through the ms-appx scheme, indicating the root of the application's package. Binary resources that are stored in another component referenced by the application can be accessed with the following syntax: <Image Source="/ResourceLibrary/jellyfish.jpg" /> The markup assumes that a component DLL named ResourceLibrary.Dll is referenced by the application and that a binary resource named jellyfish.jpg is present in its root folder. Logical resources Binary resources are not new or unique to Store apps. They've been around practically forever. Logical resources, on the other hand, is a more recent addition. First created and used by WPF, followed by the various versions of Silverlight, they are used in WinRT as well. So, what are they? Logical resources can be almost anything. These are objects, not binary chunks of data. They are stored in the ResourceDictionary objects, and can be easily accessed in XAML by using the StaticResource markup extension. Here's an example of two elements that use an identical brush: <Ellipse Grid.Row="0" Grid.Column="1"><Ellipse.Fill><LinearGradientBrush EndPoint="0,1"><GradientStop Offset="0" Color="Green" /><GradientStop Offset=".5" Color="Orange" /><GradientStop Offset="1" Color="DarkRed" /></LinearGradientBrush></Ellipse.Fill></Ellipse><Rectangle Grid.Row="1" Grid.Column="1" StrokeThickness="20"><Rectangle.Stroke><LinearGradientBrush EndPoint="0,1"><GradientStop Offset="0" Color="Green" /><GradientStop Offset=".5" Color="Orange" /><GradientStop Offset="1" Color="DarkRed" /></LinearGradientBrush></Rectangle.Stroke></Rectangle> The problem should be self-evident. We're using the same brush twice. This is bad for two reasons: If we want to change the brush, we need to do it twice (because of the duplication). Naturally, this is more severe if that brush is used by more than two elements. Two different objects are created, although just one shared object is needed. LinearGradientBrush can be turned into a logical resource (or simply a resource) and referenced by any element that requires it. To do that, the brush must be placed in a ResourceDictionary object. Fortunately, every element has a Resources property (of type ResourceDictionary) that we can use. This is typically done on the root XAML element (typically a Page), or (as we'll see in a moment) in the application's XAML (App.Xaml): <Page.Resources><LinearGradientBrush x_Key="brush1" EndPoint="0,1"><GradientStop Offset="0" Color="Green" /><GradientStop Offset=".5" Color="Orange" /><GradientStop Offset="1" Color="DarkRed" /></LinearGradientBrush></Page.Resources> Any logical resource must have a key, because it's in a dictionary. That key is specified by the x:Key XAML directive. Once placed, a resource can be accessed from any element within that Page with the StaticResource markup extension as follows: <Ellipse Fill="{StaticResource brush1}" /><Rectangle Stroke="{StaticResource brush1}" StrokeThickness="40" /> The StaticResource markup extension searches for a resource with the specified key starting from the current element. If not found, the search continues on the resources with its parent element (say a Grid). If found, the resource is selected (it is created the first time it's requested), and StaticResource is done. If not found, the parent's parent is searched and so on. If the resource is not found at the top level element (typically a Page, but can be a UserControl or something else), the search continues in the application resources (App.xaml). If not found, an exception is thrown. The search process can be summarized by the following diagram: Why is the markup extension called StaticResource? Is there a DynamicResource? DynamicResource exists in WPF only, which allows a resource to be replaced dynamically, with all those bound to it noticing the change. This is currently unsupported by WinRT. There is no single call that is equivalent to StaticResource, although it's not difficult to create one if needed. The FrameworkElement::Resources property can be consulted on any required level, navigating to the parent element using the Parent property. The Application::Resources property has special significance, since any resources defined within it can be referenced by any page or element across the entire application. This is typically used to set various defaults for a consistent look and feel. It may be tempting to store actual elements as resources (such as buttons). This should be avoided because resources are singletons within their usage container; this means referencing that button more than once within the same page will cause an exception to be thrown on the second reference, because an element can be in the visual tree just once. Resources are really intended for sharable objects, such as brushes, animations, styles, and templates. Resources can be added dynamically by using the ResourceDictionary::Insert method (on the relevant ResourceDictionary) and removed by calling ResourceDictionary::Remove. This only has an effect on subsequent {StaticResource} invocations; already bound resources are unaffected. A StaticResource markup extension can be used by a resource as well. For this to work, any StaticResource must reference a resource that was defined earlier in the XAML; this is due to the way the XAML parser works. It cannot find resources that it has not yet encountered. Managing logical resources Logical resources may be of various types, such as brushes, geometries, styles, templates, and more. Placing all those resources in a single file, such as App.xaml, hinders maintainability. A better approach would be to separate resources of different types (or based on some other criteria) from their own files. Still, they must be referenced somehow from within a common file such as App.xaml so that they are recognized. ResourceDictionary can incorporate other resource dictionaries using its MergedDictionaries property (a collection). This means a ResourceDictionary can reference as many resource dictionaries as desired and can have its own resources as well. The Source property must point to the location of ResourceDictionary. The default App.xaml created by Visual Studio contains the following (comments removed): <Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionarySource="Common/StandardStyles.xaml"/></ResourceDictionary.MergedDictionaries></ResourceDictionary></Application.Resources> Indeed, we find a file called StandardStyles.xaml in the Common folder, which hosts a bunch of logical resources, with ResourceDictionary as its root element. For this file to be considered when StaticResource is invoked, it must be referenced by another ResourceDictionary, from a Page or the application (the application is more common). The ResourceDictionary::MergedDictionaries property contains other ResourceDictionary objects, whose Source property must point to the required XAML to be included (that XAML must have ResourceDictionary as its root element). We can create our own ResourceDictionary XAML by using Visual Studio's Add New Item menu option and selecting Resource Dictionary: Duplicate keys No two objects can have the same key in the same ResourceDictionary instance. StaticResource takes the first resource it finds with the specified key, even if that key already exists in a ResourceDictionary. What about merged dictionaries? Merging different resource dictionaries may cause an issue—two or more resources with the same key that originate from different merged dictionaries. This is not an error and does not throw an exception. Instead, the selected object is the one from the last resource dictionary added (which has a resource with that key). Furthermore, if a resource in the current resource dictionary has the same key as any of the resources in its merged dictionaries, it always wins out. Here's an example: <ResourceDictionary><SolidColorBrush Color="Blue" x_Key="brush1" /><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="Resources/Brushes2.xaml" /><ResourceDictionary Source="Resources/Brushes1.xaml" /></ResourceDictionary.MergedDictionaries></ResourceDictionary> Given this markup, the resource named brush1 is a blue SolidColorBrush because it appears in the ResourceDictionary itself. This overrides any resources named brush1 in the merged dictionaries. If this blue brush did not exist, brush1 would be looked up in Brushes1.xaml first, as this is the last entry in the merged dictionaries collection. XAML containing a ResourceDictionary as its root can be loaded dynamically from a string using the static XamlReader::Load method and then added as a merged dictionary, where appropriate. Styles Consistency in user interface is an important trait; there are many facets of consistency, one of which is the consistent look and feel of controls. For example, all buttons should look roughly the same—similar colors, fonts, sizes, and so on. Styles provide a convenient way of grouping a set of properties under a single object, and then selectively (or automatically, as we'll see later) apply it to elements. Styles are always defined as resources (usually at the application level, but can also be at the Page or UserControl level). Once defined, they can be applied to elements by setting the FrameworkElement::Style property. Here's a style defined as part of the Resources section of a Page: <Page.Resources><Style TargetType="Button" x_Key="style1"><Setter Property="FontSize" Value="40" /><Setter Property="Background"><Setter.Value><LinearGradientBrush ><GradientStop Offset="0" Color="Yellow" /><GradientStop Offset="1" Color="Orange" /></LinearGradientBrush></Setter.Value></Setter><Setter Property="Foreground" Value="DarkBlue" /></Style></Page.Resources> The style has a key (style1), and must have TargetType. This is the type the style may be applied to (and any derived types). The XAML parser has a type converter that converts TargetType to a TypeName object. The main ingredient in Style is its Setters collection (which is also its ContentProperty). This collection accepts Setter objects, which need Property and Value. The property must be a dependency property (not usually a problem, as most element properties are dependency properties); these are provided as simple strings thanks to type converters used behind the scene. The above markup sets up the properties FontSize, Background (with a complex property syntax because of the LinearGradientBrush), and Foreground—all for the Button controls. Once defined, the style can be applied to elements using the usual StaticResource markup extension in XAML by setting the FrameworkElement::Style property, as in the following example: <Button Content="Styled button" Style="{StaticResource style1}" /> Readers familiar with WPF may be wondering if the TargetType property can be omitted so that a greater control range can be covered. This is unsupported in the current version of WinRT. Setting the style on an incompatible element type (such as a CheckBox control in this example) causes an exception to be thrown at page load time. If a CheckBox should also be able to use the same style, the TargetType can be changed to ButtonBase (which covers all button types). Use different styles for different elements, even if a base type seems to cover several controls. It's very likely that later some properties may need to be tweaked for a particular type, making it difficult to change the style. Build a different style for different concrete types. You can also use style inheritance (as described later) to shorten some of the markup. What happens if an element with an applied style sets a property to a different value than the one from Style? The local value wins out. This means that the following button has a font size of 30 and not 40: <Button Content="Styled button" FontSize="30"Style="{StaticResource style1}" /> Implicit (automatic) styles The previous section showed how to create a style that has a name (x:Key) and how to apply it to elements. Sometimes, however, we would like a style to be applied automatically to all elements of a certain type, to give the application a consistent look. For example, we may want all buttons to have a certain font size or background, without the need for setting the Style property of each and every button. This makes creating new buttons easier, as the developer/designer doesn't have to know what style to apply (if any, the implicit style in scope will be used automatically). To create a Style that is applied automatically, the x:Key attribute must be removed: <Style TargetType="Button">…</Style> The key still exists, as the Style property is still part of ResourceDictionary (which implements IMap<Object, Object>), but is automatically set to a TypeName object for the specified TargetType. Once the Style property is defined and any Button element (in this example) in scope for ResourceDictionary of the Style property is in, that style will be applied automatically. The element can still override any property it wishes by setting a local value. Automatic styles are applied to the exact type only, not to derived types. This means that an automatic style for ButtonBase is useless, as it's an abstract class. An element may wish to revert to its default style and not have an implicit style applied automatically. This can be achieved by setting FrameworkElement::Style to nullptr (x:Null in XAML). Style inheritance Styles support the notion of inheritance, somewhat similar to the same concept in object orientation. This is done using the BasedOn property that must point to another style to inherit from. The TargetType of the derived style must be the same as in the base style. An inherited style can add Setter objects for new properties to set, or it can provide a different value for a property that was set by the base style. Here's an example for a base style of a button: <Style TargetType="Button" x_Key="buttonBaseStyle"><Setter Property="FontSize" Value="70" /><Setter Property="Margin" Value="4" /><Setter Property="Padding" Value="40,10" /><Setter Property="HorizontalAlignment" Value="Stretch" /></Style> The following markup creates three inherited styles: <Style TargetType="Button" x_Key="numericStyle"BasedOn="{StaticResource buttonBaseStyle}"><Setter Property="Background" Value="Blue" /><Setter Property="Foreground" Value="White" /></Style><Style TargetType="Button" x_Key="operatorStyle"BasedOn="{StaticResource buttonBaseStyle}"><Setter Property="Background" Value="Orange" /><Setter Property="Foreground" Value="Black" /></Style><Style TargetType="Button" x_Key="specialStyle"BasedOn="{StaticResource buttonBaseStyle}"><Setter Property="Background" Value="Red" /><Setter Property="Foreground" Value="White" /></Style> These styles are part of a simple integer calculator application. The calculator looks like this when running: Most of the elements comprising the calculator are buttons. Here is the numeric button markup: <Button Style="{StaticResource numericStyle}" Grid.Row="1"Content="7" Click="OnNumericClick" /><Button Style="{StaticResource numericStyle}" Grid.Row="1"Grid.Column="1" Content="8" Click="OnNumericClick"/><Button Style="{StaticResource numericStyle}" Grid.Row="1"Grid.Column="2" Content="9" Click="OnNumericClick"/> The operator buttons simply use a different style: <Button Style="{StaticResource operatorStyle}" Grid.Row="3"Grid.Column="3" Content="-" Click="OnOperatorClick"/><Button Style="{StaticResource operatorStyle}" Grid.Row="4"Grid.Column="3" Content="+" Grid.ColumnSpan="2"Click="OnOperatorClick"/> The = button uses the same style as operators, but changes its background by setting a local value: <Button Style="{StaticResource operatorStyle}" Grid.Row="4"Grid.Column="1" Grid.ColumnSpan="2" Content="="Background="Green" Click="OnCalculate"/> The complete project is named StyledCalculator and can be found as part of the downloadable source for this article. Style inheritance may seem very useful, but should be used with caution. It suffers from the same issues as object oriented inheritance in a deep inheritance hierarchy—a change in a base style up in the hierarchy can affect a lot of styles, being somewhat unpredictable, leading to a maintenance nightmare. Thus, a good rule of thumb to use is to have no more than two inheritance levels. Any more than that may cause things to get out of hand. Store application styles A Store app project created by Visual Studio has a default style file named StandardStyles.xaml in the Common folder. The file includes styles for all common elements and controls the set up for a common look and feel that is recommended as a starting point. It's certainly possible to change these styles or to inherit from them if needed. WinRT styles are similar in concept to CSS used in web development to provide styling to HTML pages. The cascading part hints to the multilevel nature of CSS, much like the multilevel nature of WinRT styles (application, page, panel, specific element, and so on). Summary This article was all about XAML, the declarative language used to build user interfaces for Windows Store apps. XAML takes some time getting used to it, but its declarative nature and markup extensions cannot easily be matched by procedural code in C++ (or other languages). Designer-oriented tools, such as Expression Blend and even the Visual Studio designer make it relatively easy to manipulate XAML without actually writing XAML, but as developers and designers working with other XAML-based technologies have already realized, it's sometimes necessary to write XAML by hand, making it an important skill to acquire. Resources for Article : Further resources on this subject: WPF 4.5 Application and Windows [Article] Android Native Application API [Article] Working with Apps in Splunk [Article]
Read more
  • 0
  • 0
  • 4266
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-selecting-elements
Packt
16 Aug 2013
17 min read
Save for later

Selecting Elements

Packt
16 Aug 2013
17 min read
(For more resources related to this topic, see here.) Understanding the DOM One of the most powerful aspects of jQuery is its ability to make selecting elements in the DOM easy. The DOM serves as the interface between JavaScript and a web page; it provides a representation of the source HTML as a network of objects rather than as plain text. This network takes the form of a family tree of elements on the page. When we refer to the relationships that elements have with one another, we use the same terminology that we use when referring to family relationships: parents, children, and so on. A simple example can help us understand how the family tree metaphor applies to a document: <html> <head> <title>the title</title> </head> <body> <div> <p>This is a paragraph.</p> <p>This is another paragraph.</p> <p>This is yet another paragraph.</p> </div> </body> </html> Here, <html> is the ancestor of all the other elements; in other words, all the other elements are descendants of <html>. The <head> and <body> elements are not only descendants, but children of <html> as well. Likewise, in addition to being the ancestor of <head> and <body>, <html> is also their parent. The <p> elements are children (and descendants) of <div>, descendants of <body> and <html>, and siblings of each other. To help visualize the family tree structure of the DOM, we can use a number of software tools, such as the Firebug plugin for Firefox or the Web Inspector in Safari or Chrome. With this tree of elements at our disposal, we'll be able to use jQuery to efficiently locate any set of elements on the page. Our tools to achieve this are jQuery selectors and traversal methods. Using the $() function The resulting set of elements from jQuery's selectors and methods is always represented by a jQuery object. Such a jQuery object is very easy to work with when we want to actually do something with the things that we find on a page. We can easily bind events to these objects and add slick effects to them, as well as chain multiple modifications or effects together. Note that jQuery objects are different from regular DOM elements or node lists, and as such do not necessarily provide the same methods and properties for some tasks. In order to create a new jQuery object, we use the $() function. This function typically accepts a CSS selector as its sole parameter and serves as a factory returning a new jQuery object pointing to the corresponding elements on the page. Just about anything that can be used in a stylesheet can also be passed as a string to this function, allowing us to apply jQuery methods to the matched set of elements. Making jQuery play well with other JavaScript libraries In jQuery, the dollar sign ($) is simply an alias for jQuery. Because a $() function is very common in JavaScript libraries, conflicts could arise if more than one of these libraries were being used in a given page. We can avoid such conflicts by replacing every instance of $ with jQuery in our custom jQuery code. The three primary building blocks of selectors are tag name, ID, and class. They can be used either on their own or in combination with others. The following simple examples illustrate how these three selectors appear in code: Selector type CSS jQuery What it does Tag name p { } $('p') This selects all paragraphs in the document. ID #some-id { } $('#some-id') This selects the single element in the document that has an ID of some-id. Class .some-class { } $('.some-class') This selects all elements in the document that have a class of some-class. When we call methods of a jQuery object, the elements referred by the selector we passed to $() are looped through automatically and implicitly. Therefore, we can usually avoid explicit iteration, such as a for loop, that is so often required in DOM scripting. Now that we have covered the basics, we're ready to start exploring some more powerful uses of selectors. CSS selectors The jQuery library supports nearly all the selectors included in CSS specifications 1 through 3, as outlined on the World Wide Web Consortium's site: http://www.w3.org/Style/CSS/specs. This support allows developers to enhance their websites without worrying about which browsers might not understand more advanced selectors, as long as the browsers have JavaScript enabled. Progressive Enhancement Responsible jQuery developers should always apply the concepts of progressive enhancement and graceful degradation to their code, ensuring that a page will render as accurately, even if not as beautifully, with JavaScript disabled as it does with JavaScript turned on. We will continue to explore these concepts throughout the article. More information on progressive enhancement can be found at http://en.wikipedia.org/wiki/Progressive_enhancement. To begin learning how jQuery works with CSS selectors, we'll use a structure that appears on many websites, often for navigation – the nested unordered list: <ul id="selected-plays"> <li>Comedies <ul> <li><a href="/asyoulikeit/">As You Like It</a></li> <li>All's Well That Ends Well</li> <li>A Midsummer Night's Dream</li> <li>Twelfth Night</li> </ul> </li> <li>Tragedies <ul> <li><a href="hamlet.pdf">Hamlet</a></li> <li>Macbeth</li> <li>Romeo and Juliet</li> </ul> </li> <li>Histories <ul> <li>Henry IV (<a href="mailto:henryiv@king.co.uk">email</a>) <ul> <li>Part I</li> <li>Part II</li> </ul> <li><a href="http://www.shakespeare.co.uk/henryv.htm"> Henry V</a></li> <li>Richard II</li> </ul> </li> </ul> Notice that the first <ul> has an ID of selecting-plays, but none of the <li> tags have a class associated with them. Without any styles applied, the list looks like this: The nested list appears as we would expect it to—a set of bulleted items arranged vertically and indented according to their level. Styling list-item levels Let's suppose that we want the top-level items, and only the top-level items—Comedies, Tragedies, and Histories — to be arranged horizontally. We can start by defining a horizontal class in the stylesheet: .horizontal { float: left; list-style: none; margin: 10px; } The horizontal class floats the element to the left-hand side of the one following it, removes the bullet from it if it's a list item, and adds a 10-pixel margin on all sides of it. Rather than attaching the horizontal class directly in our HTML, we'll add it dynamically to the top-level list items only, to demonstrate jQuery's use of selectors: $(document).ready(function() { $('#selected-plays > li').addClass('horizontal '); }); Listing 2.1 We begin the jQuery code by calling $(document).ready(), which runs the function passed to it once the DOM has been loaded, but not before. The second line uses the child combinator (>) to add the horizontal class to all the top-level items only. In effect, the selector inside the $() function is saying, "Find each list item (li) that is a child (>) of the element with an ID of selected-plays (#selected-plays)". With the class now applied, the rules defined for that class in the stylesheet take effect, which in this case means that the list items are arranged horizontally rather than vertically. Now our nested list looks like this: Styling all the other items—those that are not in the top level—can be done in a number of ways. Since we have already applied the horizontal class to the top-level items, one way to select all sub-level items is to use a negation pseudo-class to identify all list items that do not have a class of horizontal. Note the addition of the third line of code: $(document).ready(function() { $('#selected-plays > li').addClass('horizontal'); $('#selected-plays li:not(.horizontal)').addClass('sub- level');li:not(.horizontal)').addClass('sub-level'); }); Listing 2.2 This time we are selecting every list item (<li>) that: Is a descendant of the element with an ID of selected-plays (#selected-plays) Does not have a class of horizontal (:not(.horizontal)) When we add the sub-level class to these items, they receive the shaded background defined in the stylesheet: .sub-level { background: #ccc; } Now the nested list looks like this: Attribute selectors Attribute selectors are a particularly helpful subset of CSS selectors. They allow us to specify an element by one of its HTML attributes, such as a link's title attribute or an image's alt attribute. For example, to select all images that have an alt attribute, we write the following: $('img[alt]') Styling links Attribute selectors accept a wildcard syntax inspired by regular expressions for identifying the value at the beginning (^) or end ($) of a string. They can also take an asterisk (*) to indicate the value at an arbitrary position within a string or an exclamation mark (!) to indicate a negated value. Let's say we want to have different styles for different types of links. We first define the styles in our stylesheet: a { color: #00c; } a.mailto { background: url(images/email.png) no-repeat right top; padding-right: 18px; } a.pdflink { background: url(images/pdf.png) no-repeat right top; padding-right: 18px; } a.henrylink { background-color: #fff; padding: 2px; border: 1px solid #000; } Then, we add the three classes—mailto, pdflink, and henrylink—to the appropriate links using jQuery. To add a class for all e-mail links, we construct a selector that looks for all anchor elements (a) with an href attribute ([href]) that begins with mailto: (^="mailto:"), as follows: $(document).ready(function() { $('a[href^="mailto:"]').addClass('mailto'); }); Listing 2.3 Because of the rules defined in the page's stylesheet, an envelope image appears after the mailto: link on the page. To add a class for all the links to PDF files, we use the dollar sign rather than the caret symbol. This is because we're selecting links with an href attribute that ends with .pdf: $(document).ready(function() { $('a[href^="mailto:"]').addClass('mailto'); $('a[href$=".pdf"]').addClass('pdflink'); }); Listing 2.4 The stylesheet rule for the newly added pdflink class causes an Adobe Acrobat icon to appear after each link to a PDF document, as shown in the following screenshot: Attribute selectors can be combined as well. We can, for example, add the class henrylink to all links with an href value that both starts with http and contains henry anywhere: $(document).ready(function() { $('a[href^="mailto:"]').addClass('mailto'); $('a[href$=".pdf"]').addClass('pdflink'); $('a[href^="http"][href*="henry"]') .addClass('henrylink'); }); }); Listing 2.5 With the three classes applied to the three types of links, we should see the following: Note the PDF icon to the right-hand side of the Hamlet link, the envelope icon next to the email link, and the white background and black border around the Henry V link. Custom selectors To the wide variety of CSS selectors, jQuery adds its own custom selectors. These custom selectors enhance the already impressive capabilities of CSS selectors to locate page elements in new ways. Performance note When possible, jQuery uses the native DOM selector engine of the browser to find elements. This extremely fast approach is not possible when custom jQuery selectors are used. For this reason, it is recommended to avoid frequent use of custom selectors when a native option is available and performance is very important. Most of the custom selectors allow us to choose one or more elements from a collection of elements that we have already found. The custom selector syntax is the same as the CSS pseudo-class syntax, where the selector starts with a colon (:). For example, to select the second item from a set of <div> elements with a class of horizontal, we write this: $('div.horizontal:eq(1)') Note that :eq(1) selects the second item in the set because JavaScript array numbering is zero-based, meaning that it starts with zero. In contrast, CSS is one-based, so a CSS selector such as $('div:nth-child(1)') would select all div selectors that are the first child of their parent. Because it can be difficult to remember which selectors are zero-based and which are one-based, we should consult the jQuery API documentation at http://api.jquery.com/category/selectors/ when in doubt. Styling alternate rows Two very useful custom selectors in the jQuery library are :odd and :even. Let's take a look at how we can use one of them for basic table striping given the following tables: <h2>Shakespeare's Plays</h2> <table> <tr> <td>As You Like It</td> <td>Comedy</td> <td></td> </tr> <tr> <td>All's Well that Ends Well</td> <td>Comedy</td> <td>1601</td> </tr> <tr> <td>Hamlet</td> <td>Tragedy</td> <td>1604</td> </tr> <tr> <td>Macbeth</td> <td>Tragedy</td> <td>1606</td> </tr> <tr> <td>Romeo and Juliet</td> <td>Tragedy</td> <td>1595</td> </tr> <tr> <td>Henry IV, Part I</td> <td>History</td> <td>1596</td> </tr> <tr> <td>Henry V</td> <td>History</td> <td>1599</td> </tr> </table> <h2>Shakespeare's Sonnets</h2> <table> <tr> <td>The Fair Youth</td> <td>1–126</td> </tr> <tr> <td>The Dark Lady</td> <td>127–152</td> </tr> <tr> <td>The Rival Poet</td> <td>78–86</td> </tr> </table> With minimal styles applied from our stylesheet, these headings and tables appear quite plain. The table has a solid white background, with no styling separating one row from the next, as shown in the following screenshot: Now we can add a style to the stylesheet for all the table rows and use an alt class for the odd rows: tr { background-color: #fff; } .alt { background-color: #ccc; } Finally, we write our jQuery code, attaching the class to the odd-numbered table rows (<tr> tags): $(document).ready(function() { $('tr:even').addClass('alt'); }); Listing 2.6 But wait! Why use the :even selector for odd-numbered rows? Well, just as with the :eq() selector, the :even and :odd selectors use JavaScript's native zero-based numbering. Therefore, the first row counts as zero (even) and the second row counts as one (odd), and so on. With this in mind, we can expect our simple bit of code to produce tables that look like this: Note that for the second table, this result may not be what we intend. Since the last row in the Plays table has the alternate gray background, the first row in the Sonnets table has the plain white background. One way to avoid this type of problem is to use the :nth-child() selector instead, which counts an element's position relative to its parent element rather than relative to all the elements selected so far. This selector can take a number, odd, or even as its argument: $(document).ready(function() { $('tr:nth-child(odd)').addClass('alt'); }); Listing 2.7 As before, note that :nth-child() is the only jQuery selector that is one-based. To achieve the same row striping as we did earlier—except with consistent behavior for the second table—we need to use odd rather than even as the argument. With this selector in place, both tables are now striped nicely, as shown in the following screenshot: Finding elements based on textual content For one final custom-selector touch, let's suppose for some reason we want to highlight any table cell that referred to one of the Henry plays. All we have to do—after adding a class to the stylesheet to make the text bold and italicized ( .highlight {font-weight:bold; font-style: italic;} )—is add a line to our jQuery code using the :contains() selector: $(document).ready(function() { $('tr:nth-child(odd)').addClass('alt'); $('td:contains(Henry)').addClass('highlight'); }); Listing 2.8 So, now we can see our lovely striped table with the Henry plays prominently featured: It's important to note that the :contains() selector is case sensitive. Using $('td:contains(henry)') instead, without the uppercase "H", would select no cells. Admittedly, there are ways to achieve the row striping and text highlighting without jQuery—or any client-side programming, for that matter. Nevertheless, jQuery, along with CSS, is a great alternative for this type of styling in cases where the content is generated dynamically and we don't have access to either the HTML or server-side code. Form selectors The capabilities of custom selectors are not limited to locating elements based on their position. For example, when working with forms, jQuery's custom selectors and complementary CSS3 selectors can make short work of selecting just the elements we need. The following table describes a handful of these form selectors: Selector Match :Input Input, text area, select, and button elements :button Button elements and input elements with a type attribute equal to button :enabled Form elements that are enabled :disabled Form elements that are disabled :checked Radio buttons or checkboxes that are checked :selected Option elements that are selected As with the other selectors, form selectors can be combined for greater specificity. We can, for example, select all checked radio buttons (but not checkboxes) with $('input[type="radio"]:checked') or select all password inputs and disabled text inputs with $('input[type="password"], input[type="text"]:disabled'). Even with custom selectors, we can use the same basic principles of CSS to build the list of matched elements. Summary With the techniques that we have covered in this article, we should now be able to locate sets of elements on the page in a variety of ways. In particular, we learned how to style top-level and sub-level items in a nested list by using basic CSS selectors, how to apply different styles to different types of links by using attribute selectors, add rudimentary striping to a table by using either the custom jQuery selectors :odd and :even or the advanced CSS selector :nth-child(), and highlight text within certain table cells by chaining jQuery methods. Resources for Article: Further resources on this subject: Using jQuery and jQueryUI Widget Factory plugins with RequireJS [Article] jQuery Animation: Tips and Tricks [Article] New Effects Added by jQuery UI [Article]
Read more
  • 0
  • 0
  • 1761

article-image-earning-your-first-gold
Packt
16 Aug 2013
15 min read
Save for later

Earning Your First Gold

Packt
16 Aug 2013
15 min read
(For more resources related to this topic, see here.) You need to spend gold to make gold The adage "You need to spend money to make money" holds true in World of Warcraft as well. A lot of your income will come from manufacturing processes: taking raw materials (or mats) and turning them into finished goods for the end user. To expedite this process, we will be mostly buying the materials from the Auction House, and so you will need a sizeable supply of gold when you're starting out and building inventory. Unlike in the real world, where you can get investors or loans to start up a business, in World of Warcraft you will need to collect every bit of copper yourself. It's not until you have built up this starting capital that you can truly start making significant amounts of gold. There are a few ways to go about this and some players may be able to build capital while playing as they usually do, but most players will have to work at building this capital. All the methods in this section are designed to earn you gold, with time being the only investment; no gold needs to be invested. Once you've built your starting capital, you may find yourself moving away from these sources of revenue to focus on more lucrative markets. Reselling vendor pets There are many items that you can sell on the Auction House but vendor pets will be your best bet when trying to make gold. While your mileage may vary depending on your server's economy, there are certain vendors and items that are usually profitable. As with any other tip, you will have to confirm for yourself that this is pro fitable on your server. Even before Mists of Pandaria was announced and launched with its pet battles, pets were in great demand. There are several vendors scattered throughout Azeroth that sell pets; you can then resell the pets on the Auction House for a profit. There are two reasons why pets from these vendors can typically be sold for a profit over the vendor price: Players are too lazy to venture out into the world themselves to visit these vendors and buy the pets Players don't do their research and, when they see these pets on the Auction House, are unaware that they can get these pets from the vendors We'll take a look at some examples of where you can get pets from a vendor to sell on the Auction House. Always make sure you're selling these pets for a profit. As with most methods we will go over, this tactic's effectiveness is largely determined by your server's market. Be sure to check market prices for these pets before you go out and collect them (The Undermine Journal (https://theunderminejournal.com/) will help you with market research). Neutral vendors Players from either faction will be able to access these vendors and resell their wares on their faction-specific Auction House. One of these vendors is Dealer Rashaad at the Stormspire in Netherstorm and he can be found west of the flight master at Stormspire. The following screenshot shows the map of Netherstorm, and the player icon marks the location of Dealer Rashaad: Dealer Rashaad is marked with the <Exotic Creatures> tag and sells the following pets (as presented by the vendor, from left to right, top to bottom): Parrot Cage (Senegal): Purchase for 40 silver Cat Carrier (Siamese): Purchase for 60 silver Undercity Cockroach: Purchase for 50 silver Crimson Snake: Purchase for 50 silver Brown Rabbit Crate: Purchase for 10 gold Red Moth Egg: Purchase for 10 gold Blue Dragonhawk Hatchling: Purchase for 10 gold Mana Wyrmling: Purchase for 40 gold Dealer Rashaad has associations with the faction The Consortium, and so these pets will appear cheaper, depending on your reputation with this faction (up to 20 percent off if you have Exalted reputation). Another pet vendor you should visit is Breanni (tagged as <Pet Supplies>) at Magical Menagerie in the city of Dalaran in Crystalsong Forest, Northrend. The following screenshot shows the map of Dalaran and the player icon marks the location of Breanni: Breanni sells the following pets (listed in order of appearance): Cat Carrier (Calico Cat): Purchase price 50 gold Albino Snake: Purchase price 50 gold Obsidian Hatchling: Purchase price 50 gold Breanni also sells accessories for pets but, since these are Bind on Pickup items, you will not be able to sell them on the Auction House. There are several vendors that sell only one or two pets; while you can sell many of these on the Auction House as well, you will have to determine for yourself if the profit margins are worth your time spent in collecting them. The following is a list of these pets and their vendors. Only those pets that can be purchased for gold (or silver) are included in this list as there are several that can be purchased for other currencies: Ancona Chicken: Plucky Johnson in Thousand Needles Tree Frog Box: Flik at the Darkmoon Faire Wood Frog Box: Flik at the Darkmoon Faire Winterspring Cub: Michelle De Rum in Winterspring Parrot Cage (Cockatiel): Narkk in Booty Bay To make the most of these pet vendors, buy multiples of each pet (at least three to five of each) and store the spares in a bank while you are selling them. Doing this limits the number of repeat trips you have to make and makes it more worth your while. Be sure to empty your bags as much as possible when going out to fetch these pets. While being at Friendly reputation or better with these vendors can fetch you a discount of five to 20 percent, the amount of time it takes to reach these reputations is not really worth the discount. That being said, if you have a character that you know gets a discount with these vendors, use it to collect the pets and get the five to 20 percent discount on the purchase price. If you have trouble finding any of these pets, you can go to http://www.wowhead.com, which is a database of all the items, vendors, achievements, and more. Wowhead has every vendor listed and a map of where to find the vendors.  Pets from in-game events During most in-game holidays, there is a selection of pets you can buy with the holiday-specific currencies (typically tokens). While it's likely that it won't be worth your time to gather these currencies specifically to buy these pets, only you can decide what is worth your time; you might want to have these currencies anyway. Note that these pets are related to specific events only and are not available all year round. These pets are as follows: Captured Flame: 350 Burning Blossoms (Midsummer Fire Festival) Purchasable at vendors in every major city for every major faction during the course of the Midsummer Fire Festival Feline Familiar: 150 Tricky Treats Purchasable at vendors in Undercity and Elwynn Forest as part of the Hallow's End festivities Sinister Squashling: 150 Tricky Treats Purchasable at vendors in Undercity and Elwynn Forest as part of the Hallow's End Festivities Spring Rabbit's Foot: 00 Noblegarden Chocolate Purchasable at various vendors outside every major Alliance or Horde city as part of the Noblegarden festivities Pint-Sized Pink Pachyderm: 100 Brewfest Tokens Purchasable at vendors in Dun Morogh, Durotar, Ironforge, and Orgrimmar as part of Brewfest Activities Lunar Lantern and Festival Lantern: 50 Coins of Ancestry each Purchasable at vendors in Moonglade during the Lunar Festival event Truesilver Shafted Arrow: 40 Love Tokens Purchasable at vendors in all major Alliance and Horde cities during the Love is in the Air event These pets are available in plenty during and shortly after the events, so to get the best price out of your hard work, hold on to the pets for a month or more after the event ends. Some of these pets do drop (not significantly, though) as part of the incentive for Call to Arms but the largest supply comes from the events themselves. The currencies for these pets are obtained through quests and achievements related to the event and can thus only be obtained while the event is active. Many players choose to do these events anyway (for achievements or for the sake of completion), so you might find that selling these pets is an easy way to make extra gold. If you have any problems with the quests or achievements, the posts on Wowhead will typically have advice and the writers at WoW Insider (http://wow.joystiq.com) put up guides every year for the events. Faction-specific vendors and pets Each faction, Alliance and Horde, has a selection of pets that are specific to it. While you can sell them on your home Auction House, you can often get much better prices on the neutral Auction House, where you can sell to the opposite faction because this, and faction transfers, which cost money, are the only ways for them to get the pets. Keep in mind though that the neutral Auction House charges a higher fee—they charge a 15 percent cut on sales — so be wary when selling and adjust your profi t margins accordingly. As with the faction-neutral pets, these pets are broken into two categories: Purchasable with standard currency (gold, silver, and copper) Purchasable with other currencies Alliance The list of Alliance vendors with pets available for standard currency is as follows: Donni Anthania <Crazy Cat Lady>, Elwynn Forest: Cat Carrier (Bombay): Costs 40 silver Cat Carrier (Cornish Rex): Costs 40 silver Cat Carrier (Orange Tabby): Costs 40 silver Cat Carrier (Silver Tabby): Costs 40 silver Yarlyn Amberstill, Dun Morogh: Rabbit Crate (Snowshoe): Costs 40 silver Shylenai <Owl Trainer>, Darnassus: Great Horned Owl: Costs 50 silver Hawk Owl: Costs 50 silver Sixx <Moth Keeper>, The Exodar: Blue Moth Egg: Costs 50 silver White Moth Egg: Costs 50 silver Yellow Moth Egg: Costs 50 silver Lil Timmy <Boy with kittens>, Stormwind, rare spawn: Cat Carrier (White Kitten): Costs 60 silver The White Kitten especially commands a good price on the Auction House as it's difficult to get even for Alliance players, so always keep an eye out for Lil Timmy when you are in Stormwind. Finally, for those who are champions in the Argent Tournament with the playable races on the Alliance side, you can buy pets at the Argent Tournament for 40 Champion's Seals. All the vendors can be found in the Alliance tent on the north-east corner of the Argent Tournament grounds. The following screenshot shows the map of Icecrown; the player icon marks the location of the Alliance team: The pets available to Alliance players are as follows: Teldrassil Sproutling, Darnassus Mechanopeep, Gnomeregan Ammen Vale Lashling, Exodar Elwynn Lamb, Stormwind Dun Morogh Cub, Ironforge? Shimmering Wyrmling, Silver Covenant The Argent Tournament champions do well on the Alliance Auction House as well since no one plays the Argent Tournament any more and unlocking the pets requires a significant amount of work. Horde The list of Horde vendors with pets available for standard currency is as follows: Xan'tish <Snake Vendor>, Orgrimmar: Black Kingsnake: 50 silver Brown Snake: 50 silver Crimson Snake*: 50 silver Halpa <Prairie Dog Vendor>, Thunder Bluff: Prairie Dog Whistle: 50 silver Jeremiah Payson <Cockroach Vendor>, Undercity: Undercity Cockroach*: 50 silver Jilanne, Eversong Woods: Golden Dragonhawk Hatchling: 50 silver Red Dragonhawk Hatchling: 50 silver Silver Dragonhawk Hatchling: 50 silver Pets with an asterisk (*) next to them can also be purchased from a faction-neutral vendor and so may not get the same price on the neutral Auction House. Champions of the Horde's main races can get pets from the Argent Tournament for 40 Champion's Seals. To be able to buy any of these pets, a player must be a champion of the race that the particular pet is associated with. All the vendors for these pets can be found in the Horde tent at the Argent Tournament on the south-east corner of the grounds. The following screenshot shows the map of Icecrown; the player icon marks the location of the Horde tent: Fishing Fishing, one of the original secondary professions, is a convenient way to make gold with no real start-up costs. You don't need to level Fishing to make gold with it; you can train it and start fishing up valuable fish straightaway. Without max fishing, you can still fish from pools around Pandaria; the fish can then be sold on the Auction House to players looking to make buff foods. Make sure to only fish from pools if you don't have max fishing as a lower skill level in Fishing makes it almost impossible to pull any fish (except Golden Carp) from open waters. The following screenshot shows a character fishing from a pool in Pandaria: The Tillers, farming, and Sunsong Ranch Every player, over the course of leveling, will come across the Sunsong Ranch. The ranch is an excellent source of income for those who don't have the capital or professions to start the gold-making methods discussed later in this book. The ranch is basically 16 plots of soil (you start out with four and then unlock an additional four at every reputation level with the Tillers) where you can plant seeds for vegetables and other items such as Motes of Harmony. With the vegetables, you can either create buff food (requires 600 Cooking) or sell them on the Auction House to other players (who will more than likely be using them to create buff foods themselves). A copper saved is a copper earned A surprising amount of gold can be saved by nickel-and-diming everything in the game; when you're putting so much work into building up your pile of gold, you don't want to waste it! To keep inflation in check and the economy from getting out of hand, World of Warcraft has several gold sinks to try and keep the gold that is leaving the economy balanced with the gold entering it. One of the biggest gold sinks is armor repair, and an untold amount of gold is lost to this necessity every day. Luckily, there are ways to minimize how much gold is syphoned out of your pockets and into the repair vendors'. Vendors that are associated with factions (typically displayed in the way a player's guild would be, that is, in brackets under the name) give players discounts if they have a reputation with the faction. Discounts start at Friendly with 5 percent and continue all the way through to Exalted, which offers a 20 percent discount; and yes, this discount applies to repairs as well. What this means is that players can save up to 20 percent on their repair bills by repairing only at vendors. Obviously, you can't always get to a vendor you have Exalted reputation with but simply paying attention to where you repair can save you some serious gold. Make sure to repair before you go out into the world or get into a raid and resist the temptation of repairing between every wipe. Guilds can give many perks that provide you with ways to save gold. Guilds level 9 and higher have a perk that reduces the durability loss your gear experiences when you die or take damage. This means you need to repair your gear less often, which in turn means you have to spend less gold to keep it in good condition. Also, look into items before you buy them as sometimes, even though you can find them on a vendor, you can find them cheaper on the Auction House or vice versa. As we discussed in the previous section, there's a whole market for buying items from a vendor and selling them on the Auction House, so be an informed buyer! Similarly, there are some items, such as Disappearance Dust, which are often sold cheaper on the Auction House because it's cheaper to produce them through Inscription than it is to buy them from the vendor. Costs associated with the Auction House There are several places where you can reduce the amount of gold you lose when posting items on the Auction House. There are two ways you lose gold when posting items in the Auction House: Auction House cuts on sales: 5 percent is cut at Alliance and Horde Auction Houses 15 percent is cut at the neutral Auction House Lost deposits on expired or cancelled auctions When using the Auction House, it will benefit you greatly to be diligent in how you post. Don't use the neutral Auction House except for selling faction-specific items (the items that only players from one faction can obtain). Attempting to use the neutral Auction House for any other items will be futile; the few sales you actually make will be cut heavily and you'll waste way too much gold on deposits. On that note, it's best to limit how long you post auctions for as the longer the auction, the higher the deposit required. When an auction expires or is canceled, you don't get your deposit back, so if you know you will be canceling a lot of auctions, don't post your auctions for 48 hours; instead, post for 24 hours, if you don't have a lot of time to dedicate to the game, or for 12 hours if you can check the Auction House more frequently.
Read more
  • 0
  • 0
  • 2516

article-image-using-cameras
Packt
16 Aug 2013
11 min read
Save for later

Using Cameras

Packt
16 Aug 2013
11 min read
(For more resources related to this topic, see here.) Creating a picture-in-picture effect Having more than one viewport displayed can be useful in many situations. For example, you might want to show simultaneous events going on in different locations, or maybe you want to have a separate window for hot-seat multiplayer games. Although you could do it manually by adjusting the Normalized Viewport Rect parameters on your camera, this recipe includes a series of extra preferences to make it more independent from the user's display configuration. Getting ready For this recipe, we have prepared a package named basicLevel containing a scene. The package is in the 0423_02_01_02 folder. How to do it... To create a picture-in-picture display, just follow these steps: Import the basicLevel package into your Unity project. In the Project view, open basicScene, inside the folder 02_01_02. This is a basic scene featuring a directional light, a camera, and some geometry. Add the Camera option to the scene through the Create dropdown menu on top of the Hierarchy view, as shown in the following screenshot: Select the camera you have created and, in the Inspector view, set its Depth to 1: In the Project view, create a new C# script and rename it PictureInPicture. Open your script and replace everything with the following code: using UnityEngine;public class PictureInPicture: MonoBehaviour {public enum HorizontalAlignment{left, center, right};public enum VerticalAlignment{top, middle, bottom};public HorizontalAlignment horizontalAlignment =HorizontalAlignment.left;public VerticalAlignment verticalAlignment =VerticalAlignment.top;public enum ScreenDimensions{pixels, screen_percentage};public ScreenDimensions dimensionsIn = ScreenDimensions.pixels;public int width = 50;public int height= 50;public float xOffset = 0f;public float yOffset = 0f;public bool update = true;private int hsize, vsize, hloc, vloc;void Start (){AdjustCamera ();}void Update (){if(update)AdjustCamera ();}void AdjustCamera(){if(dimensionsIn == ScreenDimensions.screen_percentage){hsize = Mathf.RoundToInt(width * 0.01f * Screen.width);vsize = Mathf.RoundToInt(height * 0.01f * Screen.height);} else {hsize = width;vsize = height;}if(horizontalAlignment == HorizontalAlignment.left){hloc = Mathf.RoundToInt(xOffset * 0.01f *Screen.width);} else if(horizontalAlignment == HorizontalAlignment.right){hloc = Mathf.RoundToInt((Screen.width - hsize)- (xOffset * 0.01f * Screen.width));} else {hloc = Mathf.RoundToInt(((Screen.width * 0.5f)- (hsize * 0.5f)) - (xOffset * 0.01f * Screen.height));}if(verticalAlignment == VerticalAlignment.top){vloc = Mathf.RoundToInt((Screen.height -vsize) - (yOffset * 0.01f * Screen.height));} else if(verticalAlignment == VerticalAlignment.bottom){vloc = Mathf.RoundToInt(yOffset * 0.01f *Screen.height);} else {vloc = Mathf.RoundToInt(((Screen.height *0.5f) - (vsize * 0.5f)) - (yOffset * 0.01f * Screen.height));}camera.pixelRect = new Rect(hloc,vloc,hsize,vsize);}} In case you haven't noticed, we are not achieving percentage by dividing numbers by 100, but rather multiplying them by 0.01. The reason behind that is performance: computer processors are faster multiplying than dividing. Save your script and attach it to the new camera that you created previously. Uncheck the new camera's Audio Listener component and change some of the PictureInPicture parameters: change Horizontal Alignment to Right, Vertical Alignment to Top, and Dimensions In to pixels. Leave XOffset and YOffset as 0, change Width to 400 and Height to 200, as shown below: Play your scene. The new camera's viewport should be visible on the top right of the screen: How it works... Our script changes the camera's Normalized Viewport Rect parameters, thus resizing and positioning the viewport according to the user preferences. There's more... The following are some aspects of your picture-in-picture you could change. Making the picture-in-picture proportional to the screen's size If you change the Dimensions In option to screen_percentage, the viewport size will be based on the actual screen's dimensions instead of pixels. Changing the position of the picture-in-picture Vertical Alignment and Horizontal Alignment can be used to change the viewport's origin. Use them to place it where you wish. Preventing the picture-in-picture from updating on every frame Leave the Update option unchecked if you don't plan to change the viewport position in running mode. Also, it's a good idea to leave it checked when testing and then uncheck it once the position has been decided and set up. See also The Displaying a mini-map recipe. Switching between multiple cameras Choosing from a variety of cameras is a common feature in many genres: race sims, sports sims, tycoon/strategy, and many others. In this recipe, we will learn how to give players the ability of choosing an option from many cameras using their keyboard. Getting ready In order to follow this recipe, we have prepared a package containing a basic level named basicScene. The package is in the folder 0423_02_01_02. How to do it... To implement switchable cameras, follow these steps: Import the basicLevel package into your Unity project. In the Project view, open basicScene from the 02_01_02 folder. This is a basic scene featuring a directional light, a camera, and some geometry. Add two more cameras to the scene. You can do it through the Create drop-down menu on top of the Hierarchy view. Rename them cam1 and cam2. Change the cam2 camera's position and rotation so it won't be identical to cam1. Create an Empty game object by navigating to Game Object | Create Empty. Then, rename it Switchboard. In the Inspector view, disable the Camera and Audio Listener components of both cam1 and cam2. In the Project view, create a new C# script. Rename it CameraSwitch and open it in your editor. Open your script and replace everything with the following code: using UnityEngine;public class CameraSwitch : MonoBehaviour {public GameObject[] cameras;public string[] shortcuts;public bool changeAudioListener = true;void Update (){int i = 0;for(i=0; i<cameras.Length; i++){if (Input.GetKeyUp(shortcuts[i]))SwitchCamera(i);}}void SwitchCamera ( int index ){int i = 0;for(i=0; i<cameras.Length; i++){if(i != index){if(changeAudioListener){cameras[i].GetComponent<AudioListener>().enabled = false;}cameras[i].camera.enabled = false;} else {if(changeAudioListener){cameras[i].GetComponent<AudioListener>().enabled = true;}cameras[i].camera.enabled = true;}}}} Attach CameraSwitch to the Switchboard game object. In the Inspector view, set both Cameras and Shortcuts size to 3. Then, drag the scene cameras into the Cameras slots, and type 1, 2, and 3 into the Shortcuts text fields, as shown in the next screenshot. Play your scene and test your cameras. How it works... The script is very straightforward. All it does is capture the key pressed and enable its respective camera (and its Audio Listener, in case the Change Audio Listener option is checked). There's more... Here are some ideas on how you could try twisting this recipe a bit. Using a single-enabled camera A different approach to the problem would be keeping all the secondary cameras disabled and assigning their position and rotation to the main camera via a script (you would need to make a copy of the main camera and add it to the list, in case you wanted to save its transform settings). Triggering the switch from other events Also, you could change your camera from other game object's scripts by using a line of code, such as the one shown here: GameObject.Find("Switchboard").GetComponent("CameraSwitch"). SwitchCamera(1); See also The Making an inspect camera recipe. Customizing the lens flare effect As anyone who has played a game set in an outdoor environment in the last 15 years can tell you, the lens flare effect is used to simulate the incidence of bright lights over the player's field of view. Although it has become a bit overused, it is still very much present in all kinds of games. In this recipe, we will create and test our own lens flare texture. Getting ready In order to continue with this recipe, it's strongly recommended that you have access to image editor software such as Adobe Photoshop or GIMP. The source for lens texture created in this recipe can be found in the 0423_02_03 folder. How to do it... To create a new lens flare texture and apply it to the scene, follow these steps: Import Unity's Character Controller package by navigating to Assets | Import Package | Character Controller. Do the same for the Light Flares package. In the Hierarchy view, use the Create button to add a Directional Light effect to your scene. Select your camera and add a Mouse Look component by accessing the Component | Camera Control | Mouse Look menu option. In the Project view, locate the Sun flare (inside Standard Assets | Light Flares), duplicate it and rename it to MySun, as shown in the following screenshot: In the Inspector view, click Flare Texture to reveal the base texture's location in the Project view. It should be a texture named 50mmflare. Duplicate the texture and rename it My50mmflare. Right-click My50mmflare and choose Open. This should open the file (actually a.psd) in your image editor. If you're using Adobe Photoshop, you might see the guidelines for the texture, as shown here: To create the light rings, create new Circle shapes and add different Layer Effects such as Gradient Overlay, Stroke, Inner Glow, and Outer Glow. Recreate the star-shaped flares by editing the originals or by drawing lines and blurring them. Save the file and go back to the Unity Editor. In the Inspector view, select MySun, and set Flare Texture to My50mmflare: Select Directional Light and, in the Inspector view, set Flare to MySun. Play the scene and move your mouse around. You will be able to see the lens flare as the camera faces the light. How it works... We have used Unity's built-in lens flare texture as a blueprint for our own. Once applied, the lens flare texture will be displayed when the player looks into the approximate direction of the light. There's more... Flare textures can use different layouts and parameters for each element. In case you want to learn more about the Lens Flare effect, check out Unity's documentation at http://docs. unity3d.com/Documentation/Components/class-LensFlare.html. Making textures from screen content If you want your game or player to take in-game snapshots and apply it as a texture, this recipe will show you how. This can be very useful if you plan to implement an in-game photo gallery or display a snapshot of a past key moment at the end of a level (Race Games and Stunt Sims use this feature a lot). Getting ready In order to follow this recipe, please import the basicTerrain package, available in the 0423_02_04_05 folder, into your project. The package includes a basic terrain and a camera that can be rotated via a mouse. How to do it... To create textures from screen content, follow these steps: Import the Unity package and open the 02_04_05 scene. We need to create a script. In the Project view, click on the Create drop-down menu and choose C# Script. Rename it ScreenTexture and open it in your editor. Open your script and replace everything with the following code: using UnityEngine;using System.Collections;public class ScreenTexture : MonoBehaviour {public int photoWidth = 50;public int photoHeight = 50;public int thumbProportion = 25;public Color borderColor = Color.white;public int borderWidth = 2;private Texture2D texture;private Texture2D border;private int screenWidth;private int screenHeight;private int frameWidth;private int frameHeight;private bool shoot = false;void Start (){screenWidth = Screen.width;screenHeight = Screen.height;frameWidth = Mathf.RoundToInt(screenWidth * photoWidth *0.01f);frameHeight = Mathf.RoundToInt(screenHeight * photoHeight* 0.01f);texture = new Texture2D (frameWidth,frameHeight,TextureFormat.RGB24,false);border = new Texture2D (1,1,TextureFormat.ARGB32, false);border.SetPixel(0,0,borderColor);border.Apply();}void Update (){if (Input.GetKeyUp(KeyCode.Mouse0))StartCoroutine(CaptureScreen());}void OnGUI (){GUI.DrawTexture(new Rect((screenWidth*0.5f)-(frameWidth*0.5f) - borderWidth*2,((screenHeight*0.5f)-(frameHeight*0.5f)) - borderWidth,frameWidth + borderWidth*2,borderWidth),border,ScaleMode.StretchToFill);GUI.DrawTexture(new Rect((screenWidth*0.5f)-(frameWidth*0.5f) - borderWidth*2,(screenHeight*0.5f)+(frameHeight*0.5f),frameWidth + borderWidth*2,borderWidth),border,ScaleMode.StretchToFill);GUI.DrawTexture(new Rect((screenWidth*0.5f)-(frameWidth*0.5f)- borderWidth*2,(screenHeight*0.5f)-(frameHeight*0.5f),borderWidth,frameHeight),border,ScaleMode.StretchToFill);GUI.DrawTexture(new Rect((screenWidth*0.5f)+(frameWidth*0.5f),(screenHeight*0.5f)-(frameHeight*0.5f),borderWidth,frameHeight),border,ScaleMode.StretchToFill);if(shoot){GUI.DrawTexture(new Rect (10,10,frameWidth*thumbProportion*0.01f,frameHeight*thumbProportion* 0.01f),texture,ScaleMode.StretchToFill);}}IEnumerator CaptureScreen (){yield return new WaitForEndOfFrame();texture.ReadPixels(new Rect((screenWidth*0.5f)-(frameWidth*0.5f),(screenHeight*0.5f)-(frameHeight*0.5f),frameWidth,frameHeight),0,0);texture.Apply();shoot = true;}} Save your script and apply it to the Main Camera game object. In the Inspector view, change the values for the Screen Capturecomponent, leaving Photo Width and Photo Height as 25 and Thumb Proportion as 75, as shown here: Play the scene. You will be able to take a snapshot of the screen (and have it displayed on the top-left corner) by clicking the mouse button. How it works... Clicking the mouse triggers a function that reads pixels within the specified rectangle and applies them into a texture that is drawn by the GUI. There's more... Apart from displaying the texture as a GUI element, you could use it in other ways. Applying your texture to a material You apply your texture to an existing object's material by adding a line similar to GameObject.Find("MyObject").renderer.material.mainTexture = texture; at the end of the CaptureScreen function. Using your texture as a screenshot You can encode your texture as a PNG image file and save it. Check out Unity's documentation on this feature at http://docs.unity3d.com/Documentation/ScriptReference/ Texture2D.EncodeToPNG.html.
Read more
  • 0
  • 0
  • 11834

article-image-using-specular-unity
Packt
16 Aug 2013
14 min read
Save for later

Using Specular in Unity

Packt
16 Aug 2013
14 min read
(For more resources related to this topic, see here.) The specularity of an object surface simply describes how shiny it is. These types of effects are often referred to as view-dependent effects in the Shader world. This is because in order to achieve a realistic Specular effect in your Shaders, you need to include the direction the camera or user is facing the object's surface. Although Specular requires one more component to achieve its visual believability, which is the light direction. By combining these two directions or vectors, we end up with a hotspot or highlight on the surface of the object, half way between the view direction and the light direction. This half-way direction is called the half vector and is something new we are going to explore in this article, along with customizing our Specular effects to simulate metallic and cloth Specular surfaces. Utilizing Unity3D's built-in Specular type Unity has already provided us with a Specular function we can use for our Shaders. It is called the BlinnPhong Specular lighting model. It is one of the more basic and efficient forms of Specular, which you can find used in a lot of games even today. Since it is already built into the Unity Surface Shader language, we thought it is best to start with that first and build on it. You can also find an example in the Unity reference manual, but we will go into a bit more depth with it and explain where the data is coming from and why it is working the way it is. This will help you to get a nice grounding in setting up Specular, so that we can build on that knowledge in the future recipes in this article. Getting ready Let's start by carrying out the following: Create a new Shader and give it a name. Create a new Material, give it a name, and assign the new Shader to its shaper property. Then create a sphere object and place it roughly at world center. Finally, let's create a directional light to cast some light onto our object. When your assets have been set up in Unity, you should have a scene that resembles the following screenshot: How to do it… Begin by adding the following properties to the Shader's Properties block: We then need to make sure we add the variables to the CGPROGRAM block, so that we can use the data in our new properties inside our Shader's CGPROGRAM block. Notice that we don't need to declare the _SpecColor property as a variable. This is because Unity has already created this variable for us in the built-in Specular model. All we need to do is declare it in our Properties block and it will pass the data along to the surf() function. Our Shader now needs to be told which lighting model we want to use to light our model with. You have seen the Lambert lighting model and how to make your own lighting model, but we haven't seen the BlinnPhong lighting model yet. So, let's add BlinnPhong to our #pragma statement like so: We then need to modify our surf() function to look like the following: How it works… This basic Specular is a great starting point when you are prototyping your Shaders, as you can get a lot accomplished in terms of writing the core functionality of the Shader, while not having to worry about the basic lighting functions. Unity has provided us with a lighting model that has already taken the task of creating your Specular lighting for you. If you look into the UnityCG.cginc file found in your Unity's install directory under the Data folder, you will notice that you have Lambert and BlinnPhong lighting models available for you to use. The moment you compile your Shader with the #pragma surface surf BlinnPhong, you are telling the Shader to utilize the BlinnPhong lighting function in the UnityCG.cginc file, so that we don't have to write that code over and over again. With your Shader compiled and no errors present, you should see a result similar to the following screenshot: Creating a Phong Specular type The most basic and performance-friendly Specular type is the Phong Specular effect. It is the calculation of the light direction reflecting off of the surface compared to the user's view direction. It is a very common Specular model used in many applications, from games to movies. While it isn't the most realistic in terms of accurately modeling the reflected Specular, it gives a great approximation that performs well in most situations. Plus, if your object is further away from the camera and the need for a very accurate Specular isn't needed, this is a great way to provide a Specular effect on your Shaders. In this article, we will be covering how to implement the per vertex version of the and also see how to implement the per pixel version using some new parameters in the surface Shader's Input struct. We will see the difference and discuss when and why to use these two different implementations for different situations. Getting ready Create a new Shader, Material, and object, and give them appropriate names so that you can find them later. Finally, attach the Shader to the Material and the Material to the object. To finish off your new scene, create a new directional light so that we can see our Specular effect as we code it. How to do it… You might be seeing a pattern at this point, but we always like to start out with our most basic part of the Shader writing process: the creation of properties. So, let's add the following properties to the Shader: We then have to make sure to add the corresponding variables to our CGPROGRAM block inside our SubShader block. Now we have to add our custom lighting model so that we can compute our own Phong Specular. Add the following code to the Shader's SubShader() function. Don't worry if it doesn't make sense at this point; we will cover each line of code in the next section: Finally, we have to tell the CGPROGRAM block that it needs to use our custom lighting function instead of one of the built-in ones. We do this by changing the #pragma statement to the following: The following screenshot demonstrates the result of our custom Phong lighting model using our own custom reflection vector: How it works… Let's break down the lighting function by itself, as the rest of the Shader should be pretty familiar to you at this point. We simply start by using the lighting function that gives us the view direction. Remember that Unity has given you a set of lighting functions that you can use, but in order to use them correctly you have to have the same arguments they provide. Refer to the following table, or go to http://docs.unity3d.com/Documentation/Components/SL-SurfaceShaderLighting.html: Not view Dependent half4 Lighting Name You choose (SurfaceOutput s, half3 lightDir, half atten); View Dependent half4 Lighting Name You choose (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten); In our case, we are doing a Specular Shader, so we need to have the view-dependent lighting function structure. So, we have to write: This will tell the Shader that we want to create our own view-dependent Shader. Always make sure that your lighting function name is the same in your lighting function declaration and the #pragma statement, or Unity will not be able to find your lighting model. The lighting function then begins by declaring the usual Diffuse component by dotting the vertex normal with the light direction or vector. This will give us a value of 1 when a normal on the model is facing towards the light, and a value of -1 when facing away from the light direction. We then calculate the reflection vector taking the vertex normal, scaling it by 2.0 and by the diff value, then subtracting the light direction from it. This has the effect of bending the normal towards the light; so as a vertex normal is pointing away from the light, it is forced to look at the light. Refer to the following screenshot for a more visual representation. The script that produces this debug effect is included at the book's support page at www.packtpub.com/support. Then all we have left to do is to create the final spec's value and color. To do this, we dot the reflection vector with the view direction and take it to a power of _SpecPower. Finally, we just multiply the _SpecularColor.rgb value over the spec value to get our final Specular highlight. The following screenshot displays the final result of our Phong Specular calculation isolated out in the Shader: Creating a BlinnPhong Specular type Blinn is another more efficient way of calculating and estimating specularity. It is done by getting the half vector from the view direction and the light direction. It was brought into the world of Cg by a man named Jim Blinn. He found that it was much more efficient to just get the half vector instead of calculating our own reflection vectors. It cut down on both code and processing time. If you actually look at the built-in BlinnPhong lighting model included in the UnityCG.cginc file, you will notice that it is using the half vector as well, hence the reason why it is named BlinnPhong. It is just a simpler version of the full Phong calculation. Getting ready This time, instead of creating a whole new scene, let's just use the objects and scene we have, and create a new Shader and Material and name them BlinnPhong. Once you have a new Shader, double-click on it to launch MonoDevelop, so that we can start to edit our Shader. How to do it… First, we need to add our own properties to the Properties block, so that we can control the look of the Specular highlight. Then, we need to make sure that we have created the corresponding variables inside our CGPROGRAM block, so that we can access the data from our Properties block, inside of our subshader. Now it's time to create our custom lighting model that will process our Diffuse and Specular calculations. To complete our Shader, we will need to tell our CGPROGRAM block to use our custom lighting model rather than a built-in one, by modifying the #pragma statement with the following code: The following screenshot demonstrates the results of our BlinnPhong lighting model: How it works… The BlinnPhong Specular is almost exactly like the Phong Specular, except that it is more efficient because it uses less code to achieve almost the same effect. You will find this approach nine times out of ten in today's modern Shaders, as it is easier to code and lighter on the Shader performance. Instead of calculating our own reflection vector, we are simply going to get the vector half way between the view direction and the light direction, basically simulating the reflection vector. It has actually been found that this approach is more physically accurate than the last approach, but we thought it is necessary to show you all the possibilities. So to get the half vector, we simply need to add the view direction and the light direction together, as shown in the following code snippet: Then, we simply need to dot the vertex normal with that new half vector to get our main Specular value. After that, we just take it to a power of _SpecPower and multiply it by the Specular color variable. It's much lighter on the code and much lighter on the math, but still gives us a nice Specular highlight that will work for a lot of real-time situations. Masking Specular with textures Now that we have taken a look at how to create a Specular effect for our Shaders, let's start to take a look into the ways in which we can start to modify our Specular and give more artistic control over its final visual quality. In this next recipe, we will look at how we can use textures to drive our Specular and Specular power attributes. The technique of using Specular textures is seen in most modern game development pipelines because it allows the 3D artists to control the final visual effect on a per-pixel basis. This provides us with a way in which we can have a mat-type surface and a shiny surface all in one Shader; or, we can drive the width of the Specular or the Specular power with another texture, to have one surface with a broad Specular highlight and another surface with a very sharp, tiny highlight. There are many effects one can achieve by mixing his/her Shader calculations with textures, and giving artists the ability to control their Shader's final visual effect is key to an efficient pipeline. Let's see how we can use textures to drive our Specular lighting models. This article will introduce you to some new concepts, such as creating your own Input struct, and learning how the data is being passed around from the output struct, to the lighting function, to the Input struct, and to the surf() function. Understanding the flow of data between these core Surface Shader elements is core to a successful Shader pipeline. Getting ready We will need a new Shader, Material, and another object to apply our Shader and Material on to. With the Shader and Material connected and assigned to your object in your scene, double-click the Shader to bring it up in MonoDevelop. We will also need a Specular texture to use. Any texture will do as long as it has some nice variation in colors and patterns. The following screenshot shows the textures we are using for this recipe: How to do it… First, let's populate our Properties block with some new properties. Add the following code to your Shader's Properties block: We then need to add the corresponding variables to the subshader, so that we can access the data from the properties in our Properties block. Add the following code, just after the #pragma statement: Now we have to add our own custom Output struct. This will allow us to store more data for use between our surf function and our lighting model. Don't worry if this doesn't make sense just yet. We will cover the finer details of this Output struct in the next section of the article. Place the following code just after the variables in the SubShader block: Just after the Output struct we just entered, we need to add our custom lighting model. In this case, we have a custom lighting model called LightingCustomPhong. Enter the following code just after the Output struct we just created: In order for our custom lighting model to work, we have to tell the SubShader block which lighting model we want to use. Enter the following code to the #pragma statement so that it loads our custom lighting model: Since we are going to be using a texture to modify the values of our base Specular calculation, we need to store another set of UVs for that texture specifically. This is done inside the Input struct by placing the word uv in front of the variable's name that is holding the texture. Enter the following code just after your custom lighting model: To finish off the Shader, we just need to modify our surf() function with the following code. This will let us pass the texture information to our lighting model function, so that we can use the pixel values of the texture to modify our Specular values in the lighting model function: The following screenshot shows the result of masking our Specular calculations with a color texture and its channel information. We now have a nice variation in Specular over the entire surface, instead of just a global value for the Specular:
Read more
  • 0
  • 0
  • 12812
Packt
14 Aug 2013
3 min read
Save for later

nopCommerce – The Public-facing Storefront

Packt
14 Aug 2013
3 min read
(For more resources related to this topic, see here.) General site layout and overview When customers navigate to your store, they will be presented with the homepage. The homepage is where we'll begin to review the site layout and structure. Logo : This is your store logo. As with just about every e-commerce site, this serves as a link back to your homepage. Header links : The toolbar holds some of the most frequently used links, such as Shopping cart, Wishlist, and Account. These links are very customer focused, as this area will also show the customer's logged in status once they are registered with your site. Header menu : The menu holds various links to other important pages, such as New products, Search, and Contact us. It also contains the link to the built-in blog site. Left-side menu : The left-side menu serves as a primary navigation area. It contains the Categories and Manufacturers links as well as Tags and Polls. Center : This area is the main content of the site. It will hold category and product information, as well as the main content of the homepage. Right-side menu : The right-side menu holds links to other ancillary pages in your site, such as Contact us, About us, and News. It also holds the Newsletter signup widget. Footer : The footer holds the copyright information and the Powered by nopCommerce license tag. The naming conventions used for these areas are driven by the Cascading Style Sheet (CSS) definitions. For instance, if you look at the CSS for the Header links area, you will see a definition of header-links. nopCommerce uses layouts to define the overall site structure. A layout is a type of page used in ASP.NET MVC to define a common site template, which is then inherited across all the other pages on your site. In nopCommerce, there are several different layout pages used throughout the site. There are two main layout pages that define the core structure: Root head : This is the base layout page. It contains the header of the HTML that is generated and is responsible for loading all the CSS and JavaScript files needed for the site. Root : This layout is responsible for loading the header, footer, and contains the Master Wrapper, which contains all the other content of the page. These two layouts are common for all pages within nopCommerce, which means every page in the site will display the logo, header links, header menu, and footer. They form the foundation of the site structure. The site pages themselves will utilize one of three other layouts that determine the structure inside the Master Wrapper: Three-column : The three-column layout is what the nopCommerce homepage utilizes. It includes the right side, left side, and center areas. This layout is used primarily on the homepage. Two-column : This is the most common layout that customers will encounter. It includes the left side and center areas. This layout is used on all category and product pages as well as all the ancillary pages. One-column : This layout is used in the shopping cart and checkout pages. It includes the center area only. Changing the layout page used by certain pages requires changing the code. For instance, if we open the product page in Visual Studio, we can see the layout page being used: As you can see, the layout defined for this page is _ColumnsTwo.cshtml, the two-column layout. You can change the layout used by updating this property, for instance, to _ColumnsThree.cshtml, to use the three-column layout.
Read more
  • 0
  • 0
  • 1504

article-image-creating-courses-blackboard-learn
Packt
14 Aug 2013
10 min read
Save for later

Creating Courses in Blackboard Learn

Packt
14 Aug 2013
10 min read
(For more resources related to this topic, see here.) Courses in Blackboard Learn The basic structure of any learning management system relies on the basic course, or course shell. A course shell holds all the information and communication that goes on within our course and is the central location for all activities between students and instructors. Let's think about our course shell as a virtual house or apartment. A house or apartment is made up of different rooms where we put things that we use in our everyday life. These rooms such as the living room, kitchen, or bedrooms can be compared to content areas within our course shell. Within each of these content areas, there are items such as telephones, dishwashers, computers, or televisions that we use to interact, communicate, or complete tasks. These items would be called course tools within the course shell. These content areas and tools are available within our course shells and we can use them in the same ways. While as administrators, we won't take a deep dive into all these tools; we should know that they are available and instructors use them within their courses. Blackboard Learn offers many different ways to create courses, but to help simplify our discussion, we will classify those ways in two categories, basic and advanced. This article will discuss the course creation options that we classify as basic. Course names and course IDs When we get ready to create a course in Blackboard Learn, the system requires a few items. It requires a course name and a course ID. The first one should be self-explanatory. If you are teaching a course on "Underwater Basket Weaving" (a hobby I highly recommend), you would simply place this information into the course name. Now the course ID is a bit trickier. Think of it like a barcode that you can find on your favorite cereal. That barcode is unique and tells the checkout scanner the item you have purchased. The course ID has a similar function in Blackboard Learn. It must be unique; so if you plan to have multiple courses on "Underwater Basket Weaving", you will need to figure out a way to express the differences in each course ID. We just talked about how each course ID in Blackboard has to be unique. We as administrators will find that most Blackboard Learn instances we deal with have numerous course shells. Providing multiple courses to the users might become difficult. So we should consider creating a course ID naming convention if one isn't already in place. Our conversation will not tell you which naming convention will be best for your organization, but here are some helpful tips for us to start with: Use a symbol to separate words, acronyms, and numbers from one another. Some admins may use an underscore, period, or dash. However, whitespace, percent, ampersand, less than, greater than, equals, or plus characters are not accepted within course IDs. If you plan to collect reporting data from your instance, make sure to include the term or session and department in the course ID. Collect input from people and teams within your organization who will enroll and support users. Their feedback about a course's naming convention will help it be successful. Many organizations use a student information system, (SIS), which manages the enrollment process.   Default course properties The first item in our Course Settings area allows us to set up several of the default access options within our courses. The Default Course Properties page covers when and who has access to a course by default. Available by Default: This option gives us the ability to have a course available to enrolled students when it is created. Most administrators will have this set to No, since the instructor may not want to immediately give access to the course. Allow Guests by Default and Allow Observers by Default: The next options allow us to set guest and observer access to created courses by default. Most administrators normally set these to No because the guest access and observer role aren't used by their organizations. Default Enrollment Options: We can set default enrollment options to either allow the instructor or system administrator to enroll students or allow the student to self enroll. If we choose the former, we can give the student the ability to e-mail the instructor to request access. If we set Self Enrollment, we can set dates when this option is available and even set a default access code for students to use when they can self enroll. Now that we have these two options for default enrollment, most administrators would suggest setting the default course enrollment option to instructors or system administrators, which will allow instructors to set self enrollment within their own course. Default Duration: The Continuous option allows the course to run continuously with no start or end date set. Select Dates sets specific start and end dates for all courses. The last option called Days from the Date of Enrollment sets courses to run for a specific number of days after the student was enrolled within our Blackboard Learn environment. This is helpful if a student self enrolls in a self-paced course with a set number of days to complete it. Pitfalls of setting start and end dates When using the Start and End dates to control course duration, we may find that all users enrolled within the course will lose access. Course themes and icons If we are using the Blackboard 2012 theme, we have the ability to enable course themes within our Blackboard instance. These themes are created by Blackboard and can be applied to an instructor's course by clicking on the theme icon, seen in the following screenshot, in the upper-right corner of the content area while in a course. They have a wide variety of options, but currently administrators cannot create custom course themes. We can also select which icon sets courses will use by default in our Blackboard instance. These icon themes are created by Blackboard and will appear beside different content items and tools within the course. In the following screenshot, we can see some of the icons that make up one of the sets. Unlike the course themes, these icons will be enforced across the entire instance. Course Tools The Course Tools area offers us the ability to set what tools and content items are available within courses by default. We can also control these settings along with organizations and system tools by clicking on the Tools link under the Tools and Utilities module. Let's review what tools are available and how to enable and disable them within our courses. The options we use to set course tools are exactly same as those used in the Tools area we just mentioned. Use the information provided here to set tool availability with a page. Let's take a more detailed look into the default availability setting within this page. We have four options for each tool. Every tool has the same options. Default On: A course automatically has this tool available to users, but an instructor or leader can disable the tool within it Default Off: Users in a course will not have access to this tool by default, but the instructor or leader can enable it Always On: Instructors or leaders are unable to turn this tool off in their course or organization Always Off: Users do not see this tool in a course or organization, nor can the instructor or leader turn it on within the course Once we make the changes, we must click on the Submit button. Quick Setup Guide The Quick Setup Guide page was introduced into Blackboard 9.1 Service Pack 8. As seen in the following screenshot, it offers instructors the basic introduction into the course if they have never used Blackboard before. Most of the links are to the content from the On Demand area of the Blackboard website. We as administrators can disable this from appearing when an instructor enters the course. If we leave the guide enabled, we can add custom text to the guide, which can help educate instructors about changes, help, and support available from our organization. Custom images We can continue to customize default look and feel of our course shells with images in the course entry point and at the top of the menu. We might use these images to spotlight that our organization has been honored with an award. Here we find an example of how these images would look. Two images can be located at the bottom of the course entry page, which is the page we see after entering a course. Another image can be located at the top of the course menu. This area also allows us to make these images linkable to a website. Here's an example. Default course size limits We can also create a default course size limit for the course and the course export and archive packages within this area. Course Size Limits allows administrators to control storage space, which may be limited in some instances. When a course size limit is within 10 percent of being reached, the administrator and instructor get an e-mail notification. This notification is triggered by the disk usage task that runs once a day. After getting the notification, the instructor can remove content from the course, or the administrator can increase the course quota for that specific course. Maximum Course disk size: This option sets the amount of disk space a course shell can use for storage. This includes all course and student files within the course shell. Maximum Course Package Size: This sets the maximum amount of content from the Course Files area included in a course copy, export, or archive. Grade Center settings This area allows us to set default controls over the Grade History portion of the Grade Center. Grade history is exactly what it says. It keeps a history of the changes within the Grade Center. Most administrators recommend having grade history enabled by default because of the historical benefits. There may be a discussion within your organization to permit instructors to disable this feature within their course or clear the history altogether. Course menu and structures The course menu offers the main navigation for any course user. Our organization can create a default course menu layout for all new course shells created based on the input from instructional designers and pedagogical experts. As seen in the following screenshot, we simply edit the default menu that appears on this page. As administrators, we should pay close attention when creating a default course menu. Any additions or removals to the default menu are automatically changed without clicking on the Submit or Cancel buttons, and are applied to any courses created from that point forward. Blackboard recently introduced course structures. If enabled, these pre-built course menus are available to the instructor within their course's control panel. The course structures fall into a number of different course instruction scenarios. An example of the course structure selection interface is shown in the following screenshot:
Read more
  • 0
  • 0
  • 2285

Packt
14 Aug 2013
6 min read
Save for later

Analytics – Drawing a Frequency Distribution with MapReduce (Intermediate)

Packt
14 Aug 2013
6 min read
(For more resources related to this topic, see here.) Often, we use Hadoop to calculate analytics, which are basic statistics about data. In such cases, we walk through the data using Hadoop and calculate interesting statistics about the data. Some of the common analytics are show as follows: Calculating statistical properties like minimum, maximum, mean, median, standard deviation, and so on of a dataset. For a dataset, generally there are multiple dimensions (for example, when processing HTTP access logs, names of the web page, the size of the web page, access time, and so on, are few of the dimensions). We can measure the previously mentioned properties by using one or more dimensions. For example, we can group the data into multiple groups and calculate the mean value in each case. Frequency distributions histogram counts the number of occurrences of each item in the dataset, sorts these frequencies, and plots different items as X axis and frequency as Y axis. Finding a correlation between two dimensions (for example, correlation between access count and the file size of web accesses). Hypothesis testing: To verify or disprove a hypothesis using a given dataset. However, Hadoop will only generate numbers. Although the numbers contain all the information, we humans are very bad at figuring out overall trends by just looking at numbers. On the other hand, the human eye is remarkably good at detecting patterns, and plotting the data often yields us a deeper understanding of the data. Therefore, we often plot the results of Hadoop jobs using some plotting program. Getting ready This article assumes that you have access to a computer that has Java installed and the JAVA_HOME variable configured. Download a Hadoop distribution 1.1.x from http://hadoop.apache.org/releases.html page. Unzip the distribution, we will call this directory HADOOP_HOME. Download the sample code for the article and copy the data files. How to do it... If you have not already done so, let us upload the amazon dataset to the HDFS filesystem using the following commands: >bin/hadoopdfs -mkdir /data/>bin/hadoopdfs -mkdir /data/amazon-dataset>bin/hadoopdfs -put <SAMPLE_DIR>/amazon-meta.txt /data/amazondataset/>bin/hadoopdfs -ls /data/amazon-dataset Copy the hadoop-microbook.jar file from SAMPLE_DIR to HADOOP_HOME. Run the first MapReduce job to calculate the buying frequency. To do that run the following command from HADOOP_HOME: $ bin/hadoop jar hadoop-microbook.jar microbook.frequency.BuyingFrequencyAnalyzer/data/amazon-dataset /data/frequencyoutput1 Use the following command to run the second MapReduce job to sort the results of the first MapReduce job: $ bin/hadoop jar hadoop-microbook.jar microbook.frequency.SimpleResultSorter /data/frequency-output1 frequency-output2 You can find the results from the output directory. Copy results to HADOOP_HOME using the following command: $ bin/Hadoop dfs -get /data/frequency-output2/part-r-00000 1.data Copy all the *.plot files from SAMPLE_DIR to HADOOP_HOME. Generate the plot by running the following command from HADOOP_HOME. $gnuplot buyfreq.plot It will generate a file called buyfreq.png, which will look like the following: As the figure depicts, few buyers have brought a very large number of items. The distribution is much steeper than normal distribution, and often follows what we call a Power Law distribution. This is an example that analytics and plotting results would give us insight into, underlying patterns in the dataset. How it works... You can find the mapper and reducer code at src/microbook/frequency/BuyingFrequencyAnalyzer.java. This figure shows the execution of two MapReduce jobs. Also the following code listing shows the map function and the reduce function of the first job: public void map(Object key, Text value, Context context) throwsIOException, InterruptedException {List<BuyerRecord> records = BuyerRecord.parseAItemLine(value.toString());for(BuyerRecord record: records){context.write(new Text(record.customerID), new IntWritable(record.itemsBrought.size()));}}public void reduce(Text key, Iterable<IntWritable> values, Context context) {int sum = 0;for (IntWritableval : values) {sum += val.get();}result.set(sum);context.write(key, result);} As shown by the figure, Hadoop will read the input file from the input folder and read records using the custom formatter we introduced in the Writing a formatter (Intermediate) article. It invokes the mapper once per each record, passing the record as input. The mapper extracts the customer ID and the number of items the customer has brought, and emits the customer ID as the key and number of items as the value. Then, Hadoop sorts the key-value pairs by the key and invokes a reducer once for each key passing all values for that key as inputs to the reducer. Each reducer sums up all item counts for each customer ID and emits the customer ID as the key and the count as the value in the results. Then the second job sorted the results. It reads output of the first job as the result and passes each line as argument to the map function. The map function extracts the customer ID and the number of items from the line and emits the number of items as the key and the customer ID as the value. Hadoop will sort the key-value pairs by the key, thus sorting them by the number of items, and invokes the reducer once per key in the same order. Therefore, the reducer prints them out in the same order essentially sorting the dataset. Since we have generated the results, let us look at the plotting. You can find the source for the gnuplot file from buyfreq.plot. The source for the plot will look like the following: set terminal pngset output "buyfreq.png"set title "Frequency Distribution of Items brought by Buyer";setylabel "Number of Items Brought";setxlabel "Buyers Sorted by Items count";set key left topset log yset log xplot "1.data" using 2 title "Frequency" with linespoints Here the first two lines define the output format. This example uses png, but gnuplot supports many other terminals such as screen, pdf, and eps. The next four lines define the axis labels and the title, and the next two lines define the scale of each axis, and this plot uses log scale for both. The last line defines the plot. Here, it is asking gnuplot to read the data from the 1.data file, and to use the data in the second column of the file via using 2, and to plot it using lines. Columns must be separated by whitespaces. Here if you want to plot one column against another, for example data from column 1 against column 2, you should write using 1:2 instead of using 2. There's more... We can use a similar method to calculate the most types of analytics and plot the results. Refer to the freely available article of Hadoop MapReduce Cookbook, Srinath Perera and Thilina Gunarathne, Packt Publishing at http://www.packtpub.com/article/advanced-hadoop-mapreduce-administration for more information. Summary In this article, we have learned how to process Amazon data with MapReduce, generate data for a histogram, and plot it using gnuplot. Resources for Article : Further resources on this subject: Advanced Hadoop MapReduce Administration [Article] Comparative Study of NoSQL Products [Article] HBase Administration, Performance Tuning [Article]
Read more
  • 0
  • 0
  • 4878
article-image-using-test-fixtures-phpunit
Packt
14 Aug 2013
4 min read
Save for later

Using Test Fixtures in PHPUnit

Packt
14 Aug 2013
4 min read
(For more resources related to this topic, see here.) How to do it... Open tests/CardTest.php and add a new setUp() method and use the $cardproperty to hold the Cardfixture. <?php class CardTest extends PHPUnit_Framework_TestCase { private $card; public function setUp() { $this->card = new Card('4', 'spades'); } public function testGetNumber() { $actualNumber = $this->card->getNumber(); $this->assertEquals(4, $actualNumber, 'Number should be <4>'); } public function testGetSuit() { $actualSuit = $this->card->getSuit(); $this->assertEquals('spades', $actualSuit, 'Suit should be <spades>'); } public function testIsInMatchingSet() { $matchingCard = new Card('4', 'hearts'); $this->assertTrue($this->card->isInMatchingSet($matchingCard), '<4 of Spades> should match <4 of Hearts>'); } public function testIsNotInMatchingSet() { $matchingCard = new Card('5', 'hearts'); $this->assertFalse($this->card->isInMatchingSet($matchingCard), '<4 of Spades> should not match <5 of Hearts>'); } } How it works... You'll notice the biggest change in this method is the addition of the setUp() method. The setUp() method is run immediately before any test method in the test case. So when testGetNumber() is run, the PHPUnit framework will first execute setUp() on the same object. setUp() then initializes $this|card with a new Cardobject. $this|card is then used in the test to validate that the number is returned properly. Using setUp()in this way makes your tests much easier to maintain. If the signature of the Cardclass's constructor is changed, you will only have one place in this file to reflect that change as opposed to four separate places. You will save even more time as you add more and more tests to a single test case class. It should also be noted that a new instance of CardTest is created each time a test method is executed. Only the code in this case is being shared. The objects that setUp() creates are not shared across tests. We will talk about how to share resources across tests shortly. There is also a tearDown() method. It can be used to remove any resource you created inside your setUp() method. If you find yourself opening files, or sockets, or setting up other resources then you will need to use tearDown()to close those resources, delete file contents, or otherwise tear down your resources. This becomes very important to help keep your test suite from consuming too many resources. There is nothing quite like running out of inodes when you are running a large test suite! There's more... As we mentioned a moment ago, PHPUnit has the facility to share resources across execution of multiple tests. This is generally considered bad practice. One of the primary rules of creating tests is that tests should be independent from each other so that you can isolate and locate the code causing test failures more easily. However, there are times when the physical resources required to create a fixture become large enough to outweigh the negatives of sharing this fixture across multiple tests. When such cases arise PHPUnit provides two methods that you can override: setUpBeforeClass() and tearDownAfterClass(). These are expected to be static methods. setUpBeforeClass() will be called prior to any tests or setUp() calls being made on a given class. tearDownAfterClass() will be called once all tests have been run and the final tearDown() call has been made. If you override these methods to create new objects or resources you would need to make sure that you set these values on static members of the test case class. Also, even if you are dealing only with objects, the tearDownAfterClass() is incredibly important to implement. If you do not implement it then any object created in setUpBeforeClass() and saved to static variables will remain in memory until all tests in your test suite have run. Summary In this way, you can use shared fixtures to reduce code duplication and to reduce the code necessary to set up new tests. Resources for Article: Further resources on this subject: Testing your App [Article] A look into the high-level programming operations for the PHP language [Article] Agile with Yii 1.1 and PHP5: The TrackStar Application [Article]
Read more
  • 0
  • 0
  • 6227

article-image-quick-start-your-first-sinatra-application
Packt
14 Aug 2013
15 min read
Save for later

Quick start - your first Sinatra application

Packt
14 Aug 2013
15 min read
(For more resources related to this topic, see here.) Step 1 – creating the application The first thing to do is set up Sinatra itself, which means creating a Gemfile. Open up a Terminal window and navigate to the directory where you're going to keep your Sinatra applications. Create a directory called address-book using the following command: mkdir address-book Move into the new directory: cd address-book Create a file called Gemfile: source 'https://rubygems.org'gem 'sinatra' Install the gems via bundler: bundle install You will notice that Bundler will not just install the sinatra gem but also its dependencies. The most important dependency is Rack (http://rack.github.com/), which is a common handler layer for web servers. Rack will be receiving requests for web pages, digesting them, and then handing them off to your Sinatra application. If you set up your Bundler configuration as indicated in the previous section, you will now have the following files: .bundle: This is a directory containing the local configuration for Bundler Gemfile: As created previously Gemfile.lock: This is a list of the actual versions of gems that are installed vendor/bundle: This directory contains the gems You'll need to understand the Gemfile.lock file. It helps you know exactly which versions of your application's dependencies (gems) will get installed. When you run bundle install, if Bundler finds a file called Gemfile.lock, it will install exactly those gems and versions that are listed there. This means that when you deploy your application on the Internet, you can be sure of which versions are being used and that they are the same as the ones on your development machine. This fact makes debugging a lot more reliable. Without Gemfile.lock, you might spend hours trying to reproduce behavior that you're seeing on your deployed app, only to discover that it was caused by a glitch in a gem version that you haven't got on your machine. So now we can actually create the files that make up the first version of our application. Create address-book.rb: require 'sinatra/base'class AddressBook < Sinatra::Base get '/' do 'Hello World!' endend This is the skeleton of the first part of our application. Line 1 loads Sinatra, line 3 creates our application, and line 4 says we handle requests to '/'—the root path. So if our application is running on myapp.example.com, this means that this method will handle requests to http://myapp.example.com/. Line 5 returns the string Hello World!. Remember that a Ruby block or a method without explicit use of the return keyword will return the result of its last line of code. Create config.ru: $: << File.dirname(__FILE__)require 'address-book'run AddressBook.new This file gets loaded by rackup, which is part of the Rack gem. Rackup is a tool that runs rack-based applications. It reads the configuration from config.ru and runs our application. Line 1 adds the current directory to the list of paths where Ruby looks for files to load, line 2 loads the file we just created previously, and line 4 runs the application. Let's see if it works. In a Terminal, run the following command: bundle exec rackup -p 3000 Here rackup reads config.ru, loads our application, and runs it. We use the bundle exec command to ensure that only our application's gems (the ones in vendor/bundle) get used. Bundler prepares the environment so that the application only loads the gems that were installed via our Gemfile. The -p 3000 command means we want to run a web server on port 3000 while we're developing. Open up a browser and go to http://0.0.0.0:3000; you should see something that looks like the following screenshot: Illustration 1: The Hello World! output from the application Logging Have a look at the output in the Terminal window where you started the application. I got the following (line numbers are added for reference): 1 [2013-03-03 12:30:02] INFO WEBrick 1.3.12 [2013-03-03 12:30:02] INFO ruby 1.9.3 (2013-01-15) [x86_64-linux]3 [2013-03-03 12:30:02] INFO WEBrick::HTTPServer#start: pid=28551 port=30004 127.0.0.1 - - [03/Mar/2013 12:30:06] "GET / HTTP/1.1" 200 12 0.01425 127.0.0.1 - - [03/Mar/2013 12:30:06] "GET /favicon.ico HTTP/1.1" 404 445 0.0018 Like it or not, you'll be seeing a lot of logs such as this while doing web development, so it's a good idea to get used to noticing the information they contain. Line 1 says that we are running the WEBrick web server. This is a minimal server included with Ruby—it's slow and not very powerful so it shouldn't be used for production applications, but it will do for now for application development. Line 2 indicates that we are running the application on Version 1.9.3 of Ruby. Make sure you don't develop with older versions, especially the 1.8 series, as they're being phased out and are missing features that we will be using in this book. Line 3 tells us that the server started and that it is awaiting requests on port 3000, as we instructed. Line 4 is the request itself: GET /. The number 200 means the request succeeded—it is an HTTP status code that means Success . Line 5 is a second request created by our web browser. It's asking if the site has a favicon, an icon representing the site. We don't have one, so Sinatra responded with 404 (not found). When you want to stop the web server, hit Ctrl + C in the Terminal window where you launched it. Step 2 – putting the application under version control with Git When developing software, it is very important to manage the source code with a version control system such as Git or Mercurial. Version control systems allow you to look at the development of your project; they allow you to work on the project in parallel with others and also to try out code development ideas (branches) without messing up the stable application. Create a Git repository in this directory: git init Now add the files to the repository: git add Gemfile Gemfile.lock address-book.rb config.ru Then commit them: git commit -m "Hello World" I assume you created a GitHub account earlier. Let's push the code up to www.github.com for safe keeping. Go to https://github.com/new. Create a repo called sinatra-address-book. Set up your local repo to send code to your GitHub account: git remote add origin git@github.com:YOUR_ACCOUNT/sinatra-address-book.git Push the code: git push You may need to sort out authentication if this is your first time pushing code. So if you get an error such as the following, you'll need to set up authentication on GitHub: Permission denied (publickey) Go to https://github.com/settings/ssh and add the public key that you generated in the previous section. Now you can refresh your browser, and GitHub will show you your code as follows: Note that the code in my GitHub repository is marked with tags. If you want to follow the changes by looking at the repository, clone my repo from //github.com/joeyates/sinatra-address-book.git into a different directory and then "check out" the correct tag (indicated by a footnote) at each stage. To see the code at this stage, type in the following command: git checkout 01_hello_world If you type in the following command, Git will tell you that you have "untracked files", for example, .bundle: git status To get rid of the warning, create a file called .gitignore inside the project and add the following content: /.bundle//vendor/bundle/ Git will no longer complain about those directories. Remember to add .gitignore to the Git repository and commit it. Let's add a README file as the page is requesting, using the following steps: Create the README.md file and insert the following text: sinatra-address-book ==================== An example program of various Sinatra functionality. Add the new file to the repo: git add README.md Commit the changes: git commit -m "Add a README explaining the application" Send the update to GitHub: git push Now that we have a README file, GitHub will stop complaining. What's more is other people may see our application and decide to build on it. The README file will give them some information about what the application does. Step 3 – deploying the application We've used GitHub to host our project, but now we're going to publish it online as a working site. In the introduction, I asked you to create a Heroku account. We're now going to use that to deploy our code. Heroku uses Git to receive code, so we'll be setting up our repository to push code to Heroku as well. Now let's create a Heroku app: heroku createCreating limitless-basin-9090... done, stack is cedarhttp://limitless-basin-9090.herokuapp.com/ | git@heroku.com:limitless-basin-9090.gitGit remote heroku added My Heroku app is called limitless-basin-9090. This name was randomly generated by Heroku when I created the app. When you generate an app, you will get a different, randomly generated name. My app will be available on the Web at the http://limitless-basin-9090.herokuapp.com/ address. If you deploy your app, it will be available on an address based on the name that Heroku has generated for it. Note that, on the last line, Git has been configured too. To see what has happened, use the following command: git remote show heroku* remote heroku Fetch URL: git@heroku.com:limitless-basin-9090.git Push URL: git@heroku.com:limitless-basin-9090.git HEAD branch: (unknown) Now let's deploy the application to the Internet: git push heroku master Now the application is online for all to see: The initial version of the application, running on Heroku Step 4 – page layout with Slim The page looks a bit sad. Let's set up a standard page structure and use a templating language to lay out our pages. A templating language allows us to create the HTML for our web pages in a clearer and more concise way. There are many HTML templating systems available to the Sinatra developer: erb , haml , and slim are three popular choices. We'll be using Slim (http://slim-lang.com/). Let's add the gem: Update our Gemfile: gem 'slim' Install the gem: bundle We will be keeping our page templates as .slim files. Sinatra looks for these in the views directory. Let's create the directory, our new home page, and the standard layout for all the pages in the application. Create the views directory: mkdir views Create views/home.slim: p address book – a Sinatra application When run via Sinatra, this will create the following HTML markup: <p>address book – a Sinatra application</p> Create views/layout.slim: doctype html html head title Sinatra Address Book body == yield Note how Slim uses indenting to indicate the structure of the web page. The most important line here is as follows: == yield This is the point in the layout where our home page's HTML markup will get inserted. The yield instruction is where our Sinatra handler gets called. The result it returns (that is, the web page) is inserted here by Slim. Finally, we need to alter address-book.rb. Add the following line at the top of the file: require 'slim' Replace the get '/' handler with the following: get '/' do slim :home end Start the local web server as we did before: bundle exec rackup -p 3000 The following is the new home page: Using the Slim Templating Engine Have a look at the source for the page. Note how the results of home.slim are inserted into layout.slim. Let's get that deployed. Add the new code to Git and then add the two new files: git add views/*.slim Also add the changes made to the other files: git add address-book.rb Gemfile Gemfile.lock Commit the changes with a comment: git commit -m "Generate HTML using Slim" Deploy to Heroku: git push heroku master Check online that everything's as expected. Step 5 – styling To give a slightly nicer look to our pages, we can use Bootstrap (http://twitter.github.io/bootstrap/); it's a CSS framework made by Twitter. Let's modify views/layout.slim. After the line that says title Sinatra Address Book, add the following code: link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet"There are a few things to note about this line. Firstly, we will be using a file hosted on a Content Distribution Network (CDN ). Clearly, we need to check that the file we're including is actually what we think it is. The advantage of a CDN is that we don't need to keep a copy of the file ourselves, but if our users visit other sites using the same CDN, they'll only need to download the file once. Note also the use of // at the beginning of the link address; this is called a "protocol agnostic URL". This way of referencing the document will allow us later on to switch our application to run securely under HTTPS, without having to readjust all our links to the content. Now let's change views/home.slim to the following: div class="container" h1 address book h2 a Sinatra application We're not using Bootstrap to anywhere near its full potential here. Later on we can improve the look of the app using Bootstrap as a starting point. Remember to commit your changes and to deploy to Heroku. Step 6 – development setup As things stand, during local development we have to manually restart our local web server every time we want to see a change. Now we are going to set things up with the following steps so the application reloads after each change: Add the following block to the Gemfile: group :development do gem 'unicorn' gem 'guard' gem 'listen' gem 'rb-inotify', :require => false gem 'rb-fsevent', :require => false gem 'guard-unicorn' endThe group around these gems means they will only be installed and used in development mode and not when we deploy our application to the Web. Unicorn is a web server—it's better than WEBrick —that is used in real production environments. WEBrick's slowness can even become noticeable during development, while Unicorn is very fast. rb-inotify and rb-fsevent are the Linux and Mac OS X components that keep a check on your hard disk. If any of your application's files change, guard restarts the whole application, updating the changes. Finally, update your gems: bundle Now add Guardfile: guard :unicorn, :daemonize => true do `git ls-files`.each_line { |s| s.chomp!; watch s }end Add a configuration file for unicorn: mkdir config In config/unicorn.rb, add the following: listen 3000 Run the web server: guard Now if you make any changes, the web server will restart and you will get a notification via a desktop message. To see this, type in the following command: touch address-book.rb You should get a desktop notification saying that guard has restarted the application. Note that to shut guard down, you need to press Ctrl + D . Also, remember to add the new files to Git. Step 7 – testing the application We want our application to be robust. Whenever we make changes and deploy, we want to be sure that it's going to keep working. What's more, if something does not work properly, we want to be able to fix bugs so we know that they won't come back. This is where testing comes in. Tests check that our application works properly and also act as detailed documentation for it; they tell us what the application is intended for. Our tests will actually be called "specs", a term that is supposed to indicate that you write tests as specifications for what your code should do. We will be using a library called RSpec . Let's get it installed. Add the gem to the Gemfile: group :test do gem 'rack-test' gem 'rspec'end Update the gems so RSpec gets installed: bundle Create a directory for our specs: mkdir spec Create the spec/spec_helper.rb file: $: << File.expand_path('../..', __FILE__)require 'address-book'require 'rack/test'def app AddressBook.newendRSpec.configure do |config| config.include Rack::Test::Methodsend Create a directory for the integration specs: mkdir spec/integration Create a spec/integration/home_spec.rb file for testing the home page: require 'spec_helper'describe "Sinatra App" do it "should respond to GET" do get '/' expect(last_response).to be_ok expect(last_response.body).to match(/address book/) endend What we do here is call the application, asking for its home page. We check that the application answers with an HTTP status code of 200 (be_ok). Then we check for some expected content in the resulting page, that is, the address book page. Run the spec: bundle exec rspec Finished in 0.0295 seconds1 example, 0 failures Ok, so our spec is executed without any errors. There you have it. We've created a micro application, written tests for it, and deployed it to the Internet. Summary This article discussed how to perform the core tasks of Sinatra: handling a GET request and rendering a web page. Resources for Article : Further resources on this subject: URL Shorteners – Designing the TinyURL Clone with Ruby [Article] Building tiny Web-applications in Ruby using Sinatra [Article] Setting up environment for Cucumber BDD Rails [Article]  
Read more
  • 0
  • 0
  • 17836
Modal Close icon
Modal Close icon