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-research-techniques
Packt
21 Jan 2014
10 min read
Save for later

Research Techniques

Packt
21 Jan 2014
10 min read
(For more resources related to this topic, see here.) The design process lays out what type of information or level of detail we should be seeking at a particular point in the project. It does not explain how to get the information we need. For this, we rely on various techniques. These are exercises or methodologies that help us ask the appropriate questions and then analyze the answers we receive. These techniques will help us obtain the information we require to ensure our design solutions are on target and offer value to the end user. I have demonstrated the use of a few of these techniques in the example projects included in this article. However, since each project will require a slightly different approach, and because there are so many options available, it would be impractical to find an example that would adequately illustrate them all. There has been much written about these methodologies that is worth researching further. An experienced UX designer will know most of these and many other techniques, and should know when it is appropriate to employ them. Commonly used, effective research techniques Here is a very brief description of several methodologies aimed at helping us get the answers we seek during the research phase of a project. There are many others, and there will be many more developed as the software design industry continues to mature. I would recommend searching the Internet or other related books for more implementation details and examples of their usage. Stakeholder interviews Getting the project details from the primary stakeholders is likely the first thing we will need to do to get started on any project. The list of potential questions can be quite long. However, they usually roll up under one of the following primary questions: Who is going to use this software or site? What tasks does the user wish to accomplish? What does the maker of the software or site wish to accomplish? What technology will be used? (Are there any limitations to consider?) Why would the public use your software or site over another? What content will be needed to support the user in accomplishing their goals? If we are redesigning an existing site or application, we will likely find it valuable to seek answers to these additional questions: What features or complexities are hampering or otherwise negatively affecting the existing user experience? What additional features would the user or publisher find helpful in the next version of the product? Design tenet scorecard Design tenets are a list of the primary design attributes or qualities that are valued by the company or client we are working with. These attributes can describe the quality of interaction, visual style, tone of the text-based content, or even qualities that are a bit more technical in nature. Simply put, they can be anything that we would like to see represented in every interface we create. Here is an example scorecard: When there is misalignment on the vision or execution of a product or interface, it can be extremely helpful to put these tenets in the form of a scorecard. We then use this to grade the interface we have created against each design tenet. More often than not, one or more of the design tenets will have been neglected or entirely absent from the interface. Including this examination in our design reviews can help turn a general sense of dissatisfaction with a particular design solution into a focused discussion about specific attributes that need to be improved. This example scorecard is one that I recently created and used with a client. I managed to get everyone involved with the product development in the same room to quickly brainstorm what the company's design values were. Together, we defined seven design tenets or attributes that were desired in every interface we created. The idea being that if each of these values were adequately represented, we would have a higher likelihood of obtaining the company's goals. We would have a higher likelihood of producing a product that successfully gave the customer what they needed. I realize that this might seem to be of little value. After all, the tenets we have listed are all things that we should be striving for all of the time. However, each company will have a unique set of design attributes that they value above all others. There's a very good chance that they will not match our own personal values. So, it is important to understand what they are from the start so we can deliver a solution that matches their expectations. If we don't understand their values, we will design with our own values in mind. That doesn't always satisfy the client. Understanding the client's values may also help us understand where we need to educate them regarding the possible negative effects their particular values could have on the experience. For instance, let's say our client says they really appreciate new cutting edge interfaces. They like inventing new ways of solving problems with their software. They also say that they like clean interfaces that are not bogged down with a lot of help content or explanations. In this scenario, we can point to a potential conflict that might arise with this combination of values. We can explain that without some sort of tutorial content for this new interface, we may find we have a lot of users who just don't understand how the product is intended to work. The example scorecard I have included here offered significant value during the wireframing process of the project I was working on. The project started out fine, but I started to receive requests from one team member who thought the interface should be less guided and much more freeform. His desire for less navigation and guidance conflicted with the previously documented design tenet that stated that the product should include an "obvious task flow". Utilizing the scorecard, I was able to pinpoint where his requests were conflicting with the design attributes established by the team. It helped explain the logic of the design decisions I had made. And, it put the onus on him to justify his request with the knowledge that it was out of alignment with the team's prescribed values. In the end, it saved us a lot of time and effort. We were better able to focus on attributes of value and avoid going in directions that ran counter to those values. Competitive analysis Examining similar applications, sites, or products is a reliable way to quickly determine how much work is needed to compete in the existing marketplace. This exercise entails crawling through each product to examine and document the following: Product features of value Each product's target market What they do right and where they fail New ideas and features that will help offer a better experience Creating a summary of this research will help us create a plan to meet or exceed the competition. Reviewing the results of this research with the team and following up the review with a brainstorming session is a very effective way to kick-start some new ideas. Though our ultimate plan is to create something new that completely revolutionizes the marketplace, we often have to start by getting a simple v1 product into the marketplace. This is commonly referred to as the MVP or Minimum Viable Product. This means the product contains only those features that are essential for it to function in its most basic form. It can be easy to get caught up in the fervor to design something that beats out the competition with our initial release. There are times when this can be done. However, it is often smarter to promote a feature roadmap that plans out the evolution of our product through multiple versioned releases. As designers, we will likely need to help define how the experience will evolve through these multiple releases. We'll want to ensure that features are released in an order that will make sense to the user, and will always maintain the usability and integrity of the product. Personas and user profiles Personas are invented avatars that represent a certain segment of our end users. Using personas during the design process is a very common means of gaining an understanding of what typical customers or users look like. They do an amazing job of helping the team focus their efforts on what a particular user might need. Without them, it's easy to unknowingly have the team examine the interface from the point of view of different users. This can cause disagreement regarding what a particular interface needs to include to appropriately serve its end user. This is an easy trap to fall into. Several years ago, I found myself in this situation. I was presenting some new product designs with a co-worker. The product was addressing some very complex task flows that were not easy for a novice user to understand. A disagreement sprung up about how we were handling some of the details in the experience. After a couple of hours going back and forth about why the interface succeeded or failed, we finally figured out that we were thinking of two entirely different users. My teammate was looking at the designs through the eyes of an admin or expert user. I was attempting to design with the inexperienced user in mind. Once I understood the point of view through which he was examining the interface, I was able to adequately address his concerns by showing him the admin task flow we had previously created. The user he had in mind was actually never going to see the interface we had been reviewing. This was a costly misunderstanding that caused frustration and wasted a lot of time. Had we been using our persona's names during our conversation, it would've become obvious that we were thinking about two entirely different user profiles. Creating personas The process of creating personas starts with researching what types of users are expected to use the application or site you are creating. A quick brainstorming session with the team should be enough to get a list and description of these user types. As we examine the potential users in our list, it's common to find that we have many user types that are very similar. We'll want to consolidate those down to a number that is easy to remember by creating a representative for multiple user types. Here's an example of what this might look like. As we can see from the following example, our list of potential users is too long to be useful. 18 different user types are far too many to remember. We really need to narrow this down to something more manageable. I can't really give an ideal number of personas to develop. It will depend largely on the product. However, I would say it is common to have somewhere between three to six different personas. Summary In this article, we have covered basic concepts of research techniques that help us to obtain the information which is required to design applications and offer valuable services to the end users. Resources for Article: Further resources on this subject: Axure RP 6 Prototyping Essentials: Advanced Interactions [Article] Organizing your Balsamiq files [Article] Ten IPython essentials [Article]
Read more
  • 0
  • 0
  • 1381

article-image-overview-architecture-and-modeling-cassandra
Packt
21 Jan 2014
5 min read
Save for later

An overview of architecture and modeling in Cassandra

Packt
21 Jan 2014
5 min read
(For more resources related to this topic, see here.) Cassandra uses a peer-to-peer architecture, unlike a master-slave architecture, which is prone to single point of failure (SPOF) problems. Cassandra is deployed on multiple machines with each machine acting as a node in a cluster. Data is autosharded, that is, automatically distributed across nodes using key-based sharding, which means that the keys are used to distribute the data across the cluster. Each key-value data element in Cassandra is replicated across the cluster on other nodes (the default replication is 3) for high availability and fault tolerance. If a node goes down, the data can be served from another node having a copy of the original data. Sharding is an old concept used for distributing data across different systems. Sharding can be horizontal or vertical. In horizontal sharding, in case of RDBMS, data is distributed on the basis of rows, with some rows residing on a single machine and the other rows residing on other machines. Vertical sharding is similar to columnar storage, where columns can be stored separately in different locations. Hadoop Distributed File Systems (HDFS) use data-volumes-based sharding, where a single big file is sharded and distributed across multiple machines using the block size. So, as an example, if the block size is 64 MB, a 640 MB file will be split into 10 chunks and placed in multiple machines. The same autosharding capability is used when new nodes are added to Cassandra, where the new node becomes responsible for a specific key range of data. The details of what node holds what key ranges is coordinated and shared across the cluster using the gossip protocol. So, whenever a client wants to access a specific key, each node locates the key and its associated data quickly within a few milliseconds. When the client writes data to the cluster, the data will be written to the nodes responsible for that key range. However, if the node responsible for that key range is down or not reachable, Cassandra uses a clever solution called Hinted Handoff that allows the data to be managed by another node in the cluster and to be written back on the responsible node once that node is back in the cluster. The replication of data raises the concern of data inconsistency when the replicas might have different states for the same data. Cassandra uses mechanisms such as anti-entropy and read repair for solving this problem and synchronizing data across the replicas. Anti-entropy is used at the time of compaction, where compaction is a concept borrowed from Google BigTable. Compaction in Cassandra refers to the merging of SSTable and helps in optimizing data storage and increasing read performance by reducing the number of seeks across SSTables. Another problem that compaction solves is handling deletion in Cassandra. Unlike traditional RDBMS, all deletes in Cassandra are soft deletes, which means that the records still exist in the underlying data store but are marked with a special flag so that these deleted records do not appear in query results. The records marked as deleted records are called tombstone records. Major compactions handle these soft deletes or tombstones by removing them from the SSTable in the underlying file stores. Cassandra, like Dynamo, uses a Merkle tree data structure to represent the data state at a column family level in a node. This Merkle tree representation is used during major compactions to find the difference in the data states across nodes and reconciled. The Merkle tree or Hash tree is a data structure in the form of a tree where every non-leaf node is labeled with the hash of children nodes, allowing the efficient and secure verification of the contents of the large data structure. Cassandra, like Dynamo, falls under the AP part of the CAP theorem and offers a tunable consistency level. Cassandra provides multiple consistency levels, as illustrated in the following table: Operation ZERO ANY ONE QUORUM ALL Read Not supported Not supported Reads from one node   Read from a majority of nodes with replicas Read from all the nodes with replicas Write Asynchronous write Writes on one node including hints Writes on one node with commit log and Memtable Writes on a majority of nodes with replicas Writes on all the nodes with replicas A summary of the features in Cassandra The following table summarizes the key features of Cassandra with respect to its origins in Google BigTable and Amazon Dynamo: Feature Cassandra implementation Google BigTable Amazon Dynamo Architecture Peer-to-peer architecture, ring-based deployment architecture No Yes   Data model Multidimensional map (row,column, timestamp) -> bytes Yes   No CAP theorem AP with tunable consistency No Yes   Storage architecture SSTable, Memtables Yes   No Storage layer Local filesystem storage No No Fast reads and efficient storage Bloom filters, compactions Yes   No Programming language Java No Yes   Client programming language Multiple languages supported: Java, PHP, Python, REST, C++, .NET, and so on. Not known Not known Scalability model Horizontal scalability; multiple nodes deployment than a single machine deployment Yes   Yes   Version conflicts Timestamp field (not a vector clock as usually assumed) No No Hard deletes/updates Data is always appended using the timestamp field—deletes/updates are soft appends and are cleaned asynchronously as part of major compactions Yes   No Summary Cassandra packs the best features of two technologies proven at scale—Google BigTable and Amazon Dynamo. However, today Cassandra has evolved beyond these origins with new unique and enterprise-ready features such as Cassandra Query Language (CQL), support for collection columns, lightweight transactions, and triggers. Resources for Article: Further resources on this subject: Basic Concepts and Architecture of Cassandra [Article] About Cassandra [Article] Getting Started with Apache Cassandra [Article]
Read more
  • 0
  • 0
  • 7820

article-image-article-prototyping-recipes
Packt
21 Jan 2014
16 min read
Save for later

Prototyping Recipes

Packt
21 Jan 2014
16 min read
(For more resources related to this topic, see here.) Sketching, scanning, and prototyping Most folks start the design process by developing quick sketches of the concepts. These sketches can be elaborate or rudimentary. Oftentimes, these sketches evolve into paper prototypes that illustrate the flow or steps a user would take to complete a task. By scanning your drawings, making adjustments with your favorite image editing software (Gimp, Adobe Photoshop, and so on), and Axure, you can quickly create a clickable prototype. Getting ready To go through this recipe, you will need to have digital scans of your sketches and access to the image editing software of your choice. How to do it... You will now create a carousel including thumbnails from digital scans of simple, freehanddrawn sketches. Using your image-editing tool, first organize your images and crop them appropriately. You will have to organize the images and visualize the user flow just as you would do for paper prototypes. Start Axure and under Create New select RP File. If you already have Axure open, select File in the main menu, and then click on New, in the drop-down menu to create a new RP document. In the Sitemap, add additional child or sibling pages as necessary to complete your flow by clicking on the Add Page button icon or by right-clicking on any page in the sitemap. In the menu that appears, mouse over Add, and then click on the Child or the Sibling page. Double-click on any page title in Sitemap to select that page. You will see the wireframe for the associated page shown. While holding down the mouse button, drag the Image widget, and place it on the wireframe. Double-click on the Image widget on the wireframe, and select the appropriate scanned sketch. While holding down the mouse button, drag the Hot Spot widget, and place it over the item you would like to make clickable. While holding down the mouse button, drag the corners of the Hot Spot widget on the wireframe to the desired size. With Hot Spot selected, in the Widget Interactions and Note spane, click on Create Link…. In the Sitemap pop up, click on the associated page in the user flow. Repeat steps 7 through 10 for each region on your wireframe that you would like to make clickable. Repeat steps 4 through 11 for each page in Sitemap that you would like to make a part of the prototype. You can now choose to preview or save a copy of the prototype. To preview the prototype, click on the Preview button in the toolbar. To save a copy of the prototype, click on the Publish button in the toolbar, and select Generate HTML Files…. You can also generate the prototype by going to the main menu, selecting Publish, and clicking on Generate HTML Files…. How it works... Using this recipe, you are able to convert your paper sketches into clickable digital prototypes. Each paper sketch becomes a page in the Sitemap through the use of the Image widget. To accomplish this, you opened the scanned image with the Image widget to display your paper sketch on the page. To create clickable regions, you used Hot Spot and associated the next page in the flow using Create Link…. You used as many image map regions as clickable elements needed for the interactions on a page. Creating a dynamic Breadcrumb Master Using Masters in Axure allows you to create reusable components. When you make a change to a Master, the change is applied to all wireframes that contain that Master. Leveraging Masters can ensure the consistency of elements across your prototypes. Getting ready In this recipe you will create a dynamic Breadcrumb Master. In Axure, verify that the Widget Manager and Page Properties panes are shown. To verify, click on View in the main menu and mouse over Panes. In the pop-up menu, make sure that a check mark is next to all items, including the Widget Manager and Page Properties panes. How to do it... To create a dynamic Breadcrumb Master, first you will create new pages in your sitemap and three empty Masters (for example, Template, Header, Menu, and BreadCrumb). Next, you will place widgets on the Header, Menu, and BreadCrumb Masters. You will then place the Header, Menu, and BreadCrumb Masters onto the Template Master. Finally, you will drag the Template Master to all of the pages in Sitemap. Start Axure and under Create New select RP File. In the Sitemap create pages as follows: In the Masters pane, create four individual Masters, titled: Template, Header, Menu, and BreadCrumb, respectively, as shown in the following screenshot: Right-click on each Master you created in step 3, mouse over Drop Behaviour, and click on Lock to Master Location. This will cause the widgets in each Master to maintain the xand ycoordinates no matter where the Master is placed in a wireframe. In the Masters pane, double-click on the Header Master to select it. While holding down the mouse button, drag the Placeholder widget, and place it on the wireframe. With the Placeholder widget selected, type Home, and change the x: 10, y: 12, w: 96, and h: 30(present at the top-left of the window). In the Widget Interactions and Notes pane, click on the Shape Name text field, and type HomeLink. While holding down the mouse button, drag the Label widget, and place it at the coordinates (130,18) on the wireframe. With the Label widget selected, perform the following steps: Type BreadCrumb Prototype. In the Widget Interactions and Notes pane, click on the Shape Name text field, and type HeaderLabel. In the Widget Properties and Style pane, click on the Style tab, and then scroll to the Font section. Increase the font size to 18 by clicking on the font size dropdown, mouse over 18, and click to select: In the Masters pane, double-click on the Menu Master to select it. While holding down the mouse button, drag the Classic Menu - Horizontal widget, and place it at the coordinates (10,52) on the wireframe. In the Widget Interactions and Notes pane, click on the Menu Name text field, and type MainMenu. To name and link the primary menu item, perform the following steps: Click on the first menu item labeled File to select it, and type Primary. In the Widget Interactions and Notes pane, click on the Menu Item Name text field, and type MenuPrimary. In the Widget Interactions and Notes pane, click on the Interactions tab, and then click on Add Case…. In the Case Editor (OnClick) pop up, in Case description, rename the case description OpenPrimaryPage. In Click to add actions, click on Open Link. In Organize actions, you will see the interaction description update to Open Link in Current Window. In Configure actions, click on the radio button next to Link to a page in this design, and then click on Primary Page. Click on OK. In the Widget Properties and Style pane, click on the Style tab, and then scroll to the Font section. Increase the font size to 16 by clicking the font size dropdown, mouse over 16, and then click on it to select. To name and link the category menu item, perform the following steps: Click on the second menu item, labeled Edit, to select it, and type Category. In the Widget Interactions and Notes pane, click on the Menu Item Name text field, and type MenuCategory. In the Widget Interactions and Notes pane, click on the Interactions tab, and then click on Add Case…. In the Case Editor (OnClick) pop up, in Case description, rename the case description OpenCategoryPage. In Click to add actions, click on Open Link. In Organize actions, you will see the interaction description update to Open Link in Current Window. In Configure actions, click on the radio button next to Link to a page in this design, and then click on Category page. Click on OK. In the Widget Properties and Style pane, click on the Style tab, and then scroll to the Font section. Increase the font size to 16 by clicking the font size dropdown, mouse over 16, and then click on it to select. To name and link the content menu item, perform the following steps: Click on the third menu item labelled View to select it, and type Content. In the Widget Interactions and Notes pane, click on the Menu Item Name text field, and type MenuContent. In the Widget Interactions and Notes pane, click on the Interactions tab, and then click on Add Case…. In the Case Editor (OnClick) pop up, in Case description, rename the case description OpenContentPage. In Click to add actions, click on Open Link. In Organize actions, you will see the interaction description update to Open Link in Current Window. In Configure actions, click on the radio button next to Link to a page in this design, and then click on Content Page. Click on OK. In the Widget Properties and Style pane, click on the Style tab, and then scroll to the Font section. Increase the font size to 16 by clicking the font size dropdown, mouse over 16, and click on it to select it. To add a submenu item, right-click on the Primary menu item, and click on Add Submenu: Click on the first submenu item, and enter Secondary, and then perform the following steps: In the Widget Interactions and Notes pane, click on the Menu Item Name text field, and type MenuSecondary. In the Widget Interactions and Notes pane, click on the Interactions tab, and then click on Add Case…. In the Case Editor (OnClick) pop up, in Case description, rename the case description OpenSecondaryPage. In Click to add actions, click on Open Link. In Organize actions, you will see the interaction description update to Open Link in Current Window. In Configure actions, click on the radio button next to Link to a page in this design, and then click on Secondary Page. Click on OK. Right-click on the second and third submenu items, and click on Delete Menu Item. In the Masters pane, double-click on the BreadCrumb Master to select it. While holding down the mouse button, drag the Dynamic Panel widget, and place it on the wireframe. Change the x: and y: coordinates and w: and h: to be: With the Dynamic Panel selected, perform the following steps: In the Widget Interactions and Notes pane, click on the Dynamic Panel Name text field, and then type BreadCrumb. In the Widget Manager, rename State1 Home. Add states to Dynamic Panel as follows: Primary, Secondary, Tertiary,Category, Product, and Content. With Dynamic Panel selected, perform the following steps: Double-click on the state labeled Primary in the Dynamic Panel Manager. While holding down the mouse button, drag a Label widget and place it on the wireframe at coordinates (0,6). Enter Homeas the text on the Label widget. In the Widget Interactions and Notes pane, click on the Shape Name text field, and then type HomeBreadCrumbLink. In the Widget Interactions and Notes, pane click on the Interactions tab, and then click on Add Case…. In the Case Editor (OnClick) pop up, in Case description, rename the case description OpenHomePage. In Click to add actions, click on Open Link. In Organize actions, you will see the interaction description update to Open Link in Current Window. In Configure actions, click on the radio button next to Link to a page in this design, and click on Home page. Click on OK. You will now focus on building the Dynamic Panel states Primary, Secondary, Tertiary, Category, Product, and Content. The following screenshot shows what the Primary state will look like: To build the Dynamic Panel states Primary, Secondary, Tertiary, Category, Product, and Content, with the Dynamic Panel selected perform the following step: Repeat step 27, changing the step each time with the following information: Panel State Coordinates for Label Widget Label Text Shape Name Case description Configure Actions Link to Primary (0,6) Home HomeBreadCrumbLink OpenHomePage Home Primary (55,6) Primary PrimaryBreadCrumbLink OpenPrimaryPage Primary Page Secondary (0,6) Home HomeBreadCrumbLink OpenHomePage Home Secondary (55,6) Primary PrimaryBreadCrumbLink OpenPrimaryPage Primary Page Secondary (115,6) Secondary SecondaryBreadCrumbLink OpenSecondaryPage Secondary Page Tertiary (0,6) Home HomeBreadCrumbLink OpenHomePage Home Tertiary (55,6) Primary PrimaryBreadCrumbLink OpenPrimaryPage Primary Page Tertiary (115,6) Secondary SecondaryBreadCrumbLink OpenSecondaryPage Secondary Page Tertiary (200,6) Tertiary TertiaryBreadCrumbLink OpenTertiaryPage Tertiary Page Category (0,6) Home HomeBreadCrumbLink OpenHomePage Home Category (55,6) Category CategoryBreadCrumbLink OpenCategoryPage Category Page Product (0,6) Home HomeBreadCrumbLink OpenHomePage Home Product (55,6) Category CategoryBreadCrumbLink OpenCategoryPage Category Page Product (125,6) Product Detail DetailBreadCrumbLink OpenDetailPage Product Detail Page Content (0,6) Home HomeBreadCrumbLink OpenHomePage Home Content (55,6) Content ContnetBreadCrumbLink OpenContentPage Content Page To populate the Template Master with the component masters (for example, Header, Menu, and BreadCrumb Masters), perform the following steps: In the Masters pane, double-click on the Template Master to select it. While holding down the mouse button, drag the Header Master, and place it anywhere on the wireframe. In step 4, you specified Lock to Master Location for the Drop Behaviour of each Master. This causes the widgets in each Master to maintain their x and y coordinates no matter where the Master is placed in a wireframe. While holding down the mouse button, drag the Menu Master, and place on the wireframe. While holding down the mouse button, drag the BreadCrumb Master, and place it on the wireframe. While holding down the mouse button, drag the Template Master, and place it anywhere on the wireframe. The Template Master will align to the fixed X and Y coordinates. Below the wireframe, click on the Page Interactions tab, and double-click on the OnPageLoad interaction. In the Case Editor (OnPageLoad) pop up, perform the following steps: In Case description, rename the case description SetBreadCrumbState. In Click to add actions, click on Dynamic Panels to expand, and then click on Set Panel State. In Organize actions, you will see the interaction description update to Set Panel to State. In Configure actions under Select the panels to set the state, click on the checkbox next to the Label for the Breadcrumb (Dynamic Panel). Click on the Select the state dropdown, and mouse over Home. Click on Home to select it. You will see the interaction description under Organize actions update to read. Set Template/BreadCrumb/BreadCrumb Home. Click on OK. Repeat steps 30 to 32 for the remaining pages in Sitemap, modifying each OnPageLoad case to set the BreadCrumb state to the appropriate panel state corresponding to the selected page in Sitemap(for example, for the Primary page, the corresponding state would be Primary, and so on). You can now choose to preview or save a copy of the prototype. To preview the prototype, click on the preview button in the toolbar. To save a copy of the prototype, click on the Publish button in the toolbar, and select Generate HTML Files…. You can also generate the prototype by going to the main menu, selecting Publish, and clicking on Generate HTML Files…. How it works... For this recipe, you used Masters, a dynamic panel, a menu widget, and text widgets to create a dynamic BreadCrumb Master. You created four Masters: Template, Header, Menu, and BreadCrumb and set the behavior of each to Lock to Master Location. This retained the coordinates of the widgets placed on each Master when used on a page. The Template Master contained the Header, Menu, and BreadCrumb Masters. The Menu was labeled and linked to the corresponding pages in Sitemap. The BreadCrumb Master contained a dynamic panel that had a corresponding panel state for each of the pages in Sitemap. For each individual panel state, label widgets were used and linked to the corresponding page in the sitemap. When a page is loaded, the Page Interaction OnPageLoad event sets the state of the BreadCrumb dynamic panel to show the correct BreadCrumb state. Generating a dynamic welcome message Using variables, you can set widget values and text dynamically. For example, when a page loads, you could show the user a welcome message based on the day of the week. Getting ready In this recipe, you are going to explore using built-in variables in expressions. You will show the user a welcome message using the DayOfWeek variable. How to do it... Perform the following steps: Start Axure and under Create New select RP File. If you already have Axure open, select File in the main menu, and then click on New in the drop-down menu to create a new RP document. While holding down the mouse button, drag the Label widget, and place it on the wireframe at (53,13). With the Label widget selected, in the Widget Interactions and Notes pane, click on the field below Shape Name, and then type WelcomeText. In the Page Properties pane, click on the Page Interactions tab and double-click on the OnPageLoad interaction. The page will appear as shown in the following screenshot: In the Case Editor (OnPageLoad) pop up, in Case description, type DisplayMessage. In Click to add actions, click on Set Text. In Organize actions, you will see the interaction description update to Set Text In Configure actions, under Select the widgets to set text, click in the checkbox next to Label for the Welcome Text (Shape). In Configure actions under Set text to, set the dropdown to value, and click on the fx button to bring up the Edit Text pop up. In the Edit Text popup, enter in the text field Welcome. Today is. Click on the Insert Variable or Function... link to open the drop-down menu; scroll to Date; click on Date to expand the selection; and click on getDayOfWeek(), as shown in the following screenshot: Click on OK. You can now choose to preview or save a copy of the prototype. To preview the prototype, click on the preview button in the toolbar. To save a copy of the prototype, click on the Publish button in the toolbar, and select Generate HTML Files…. You can also generate the prototype by going to the main menu, selecting Publish, and then clicking on Generate HTML Files…. How it works... For this recipe, you used the Label widget, and using the Widget Interactions and Notes pane, you applied a label to the widget. Next in the Page Properties pane, you set a case on the OnPageLoad interaction to Set Variable/Widget value(s). Finally, in the Edit Text popup, you used a built-in variable. There's more... At times you may find that your Label widget is not displaying the built-in variable. One possible cause is that the length of the Label widget is not long enough to display all of the characters. For a list of variables available in Axure 7, visit http://www.axure.com/forum/tips-tricks-examples/8030-v7-variables-list.html
Read more
  • 0
  • 0
  • 1180

article-image-article-dart-server-with-dartling-and-mongodb
Packt
21 Jan 2014
10 min read
Save for later

Dart Server with Dartling and MongoDB

Packt
21 Jan 2014
10 min read
(For more resources related to this topic, see here.) Server Side Dart Creating a server in Dart is surprisingly simple, once the asynchronous programming with Futures is understood. Starting a server To start a server run the main function in todo_mongodb/todo_server_dartling_mongodb/bin/server.dart. void main() { db = new TodoDb(); db.open().then((_) { start(); }); } An access to a MongoDB database is prepared in the TodoDb constructor in todo_mongodb/todo_server_dartling_mongodb/lib/persistence/mongodb.dart. The database is opened, then the server is started. start() { HttpServer.bind(HOST, PORT) .then((server) { server.listen((HttpRequest request) { switch (request.method) { case "GET": handleGet(request); break; case 'POST': handlePost(request); break; case 'OPTIONS': handleOptions(request); break; default: defaultHandler(request); } }); }) .catchError(print) .whenComplete(() => print('Server at http://$HOST:$PORT')); } If there are no problems, the following message is displayed in the console of Dart Editor. Server at http://127.0.0.1:8080 The server accepts either GET or POST requests. void handleGet(HttpRequest request) { HttpResponse res = request.response; print('${request.method}: ${request.uri.path}'); addCorsHeaders(res); res.headers.contentType = new ContentType("application", "json", charset: 'utf-8'); List<Map> jsonList = db.tasks.toJson(); String jsonString = convert.JSON.encode(jsonList); print('JSON list in GET: ${jsonList}'); res.write(jsonString); res.close(); } The server, through a GET request, sends to a client CORS headers to allow a browser to send requests to different servers. void handlePost(HttpRequest request) { print('${request.method}: ${request.uri.path}'); request.listen((List<int> buffer) { var jsonString = new String.fromCharCodes(buffer); List<Map> jsonList = convert.JSON.decode(jsonString); print('JSON list in POST: ${jsonList}'); _integrateDataFromClient(jsonList); }, onError: print); } The POST request integrates data from a client to the model. _integrateDataFromClient(List<Map> jsonList) { var clientTasks = new Tasks.fromJson(db.tasks.concept, jsonList); var serverTaskList = db.tasks.toList(); for (var serverTask in serverTaskList) { var clientTask = clientTasks.singleWhereAttributeId('title', serverTask.title); if (clientTask == null) { new RemoveAction(db.session, db.tasks, serverTask).doit(); } } for (var clientTask in clientTasks) { var serverTask = db.tasks.singleWhereAttributeId('title', clientTask.title); if (serverTask != null) { if (serverTask.updated.millisecondsSinceEpoch < clientTask.updated.millisecondsSinceEpoch) { new SetAttributeAction( db.session, serverTask, 'completed', clientTask.completed).doit(); } } else { new AddAction(db.session, db.tasks, clientTask).doit(); } } } MongoDB database MongoDB is used to load all data from the database into the model of Dartling. In general, there may be more than one domain in a repository of Dartling. Also, there may be more than one model in a domain. A model has concepts with attributes and relationships between concepts. The TodoMVC model has only one concept - Task and no relationships. A model in Dartling may also be considered as an in-memory graphical database. It has actions, action pre and post validations, error handling, select data views, view update propagations, reaction events, transactions, sessions with the trans(action) past, so that undos and redos on the model may be done. You can add, remove, update, validate, find, select and order data. Actions or transactions may be used to support unrestricted undos and redos in a domain session. A transaction is an action that contains other actions. The domain allows any object to react to actions in its models. The empty Dartling model is prepared in the TodoDb constructor. TodoDb() { var repo = new TodoRepo(); domain = repo.getDomainModels('Todo'); domain.startActionReaction(this); session = domain.newSession(); model = domain.getModelEntries('Mvc'); tasks = model.tasks; } It is in the open method that the data are loaded into the model. Future open() { Completer completer = new Completer(); db = new Db('${DEFAULT_URI}${DB_NAME}'); db.open().then((_) { taskCollection = new TaskCollection(this); taskCollection.load().then((_) { completer.complete(); }); }).catchError(print); return completer.future; } In the MongoDB database there is one collection of tasks, where each task is a JSON document. This collection is defined in the TaskCollection class in mongodb.dart. The load method in this class transfers tasks from the database to the model. Future load() { Completer completer = new Completer(); dbTasks.find().toList().then((taskList) { taskList.forEach((taskMap) { var task = new Task.fromDb(todo.tasks.concept, taskMap); todo.tasks.add(task); }); completer.complete(); }).catchError(print); return completer.future; } There is only one concept in the model. Thus, the concept is entry and its entities are tasks (of the Tasks class). After the data are loaded, only the tasks entities may be used. The TodoDb class implements ActionReactionApi of Dartling. A reaction to an action in the model is defined in the react method of the TodoDb class. react(ActionApi action) { if (action is AddAction) { taskCollection.insert(action.entity); } else if (action is RemoveAction) { taskCollection.delete(action.entity); } else if (action is SetAttributeAction) { taskCollection.update(action.entity); } } } Tasks are inserted, deleted and updated in the mongoDB database in the following methods of the TaskCollection class. Future<Task> insert(Task task) { var completer = new Completer(); var taskMap = task.toDb(); dbTasks.insert(taskMap).then((_) { print('inserted task: ${task.title}'); completer.complete(); }).catchError(print); return completer.future; } Future<Task> delete(Task task) { var completer = new Completer(); var taskMap = task.toDb(); dbTasks.remove(taskMap).then((_) { print('removed task: ${task.title}'); completer.complete(); }).catchError(print); return completer.future; } Future<Task> update(Task task) { var completer = new Completer(); var taskMap = task.toDb(); dbTasks.update({"title": taskMap['title']}, taskMap).then((_) { print('updated task: ${task.title}'); completer.complete(); }).catchError(print); return completer.future; } } Dartling tasks The TodoMVC model is designed in Model Concepts. The graphical model is transformed into a JSON document. { "width":990, "height":580, "boxes":[ { "name":"Task", "entry":true, "x":85, "y":67, "width":80, "height":80, "items":[ { "sequence":10, "name":"title", "category":"identifier", "type":"String", "init":"", "essential":true, "sensitive":false }, { "sequence":20, "name":"completed", "category":"required", "type":"bool", "init":"false", "essential":true, "sensitive":false }, { "sequence":30, "name":"updated", "category":"required", "type":"DateTime", "init":"now", "essential":false, "sensitive":false } ] } ], "lines":[ ] } This JSON document is used in dartling_gen to generate the model in Dart. The lib/gen and lib/todo folders contain the generated model. The gen folder contains the generic code that should not be changed by a programmer. The todo folder contains the specific code that may be changed by a programmer. The specific code has Task and Tasks classes that are augmented by some specific code. class Task extends TaskGen { Task(Concept concept) : super(concept); Task.withId(Concept concept, String title) : super.withId(concept, title); // begin: added by hand Task.fromDb(Concept concept, Map value): super(concept) { title = value['title']; completed = value['completed']; updated = value['updated']; } Task.fromJson(Concept concept, Map value): super(concept) { title = value['title']; completed = value['completed'] == 'true' ? true : false; updated = DateTime.parse(value['updated']); } bool get left => !completed; bool get generate => title.contains('generate') ? true : false; Map toDb() { return { 'title': title, 'completed': completed, 'updated': updated }; } bool preSetAttribute(String name, Object value) { bool validation = super.preSetAttribute(name, value); if (name == 'title') { String title = value; if (validation) { validation = title.trim() != ''; if (!validation) { var error = new ValidationError('pre'); error.message = 'The title should not be empty.'; errors.add(error); } } if (validation) { validation = title.length <= 64; if (!validation) { var error = new ValidationError('pre'); error.message = 'The "${title}" title should not be longer than 64 characters.'; errors.add(error); } } } return validation; } // end: added by hand } class Tasks extends TasksGen { Tasks(Concept concept) : super(concept); // begin: added by hand Tasks.fromJson(Concept concept, List<Map> jsonList): super(concept) { for (var taskMap in jsonList) { add(new Task.fromJson(concept, taskMap)); } } Tasks get completed => selectWhere((task) => task.completed); Tasks get left => selectWhere((task) => task.left); Task findByTitleId(String title) { return singleWhereId(new Id(concept)..setAttribute('title', title)); } // end: added by hand } Client Side Dart The Todo web application may be run in the Dartium virtual machine within the Dart Editor, or as a JavaScript application run in any modern browser (todo_mongodb/todo_client_idb/web/app.html). The client application has both the model in todo_mongodb/todo_client_idb/lib/model and the view of the model in todo_mongodb/todo_client_idb/lib/view. The model has two Dart files, idb.dart for IndexedDB and model.dart for plain objects created from scratch without any model framework such as Dartling. The view is done in DOM. The application delegates the use of a local storage to the IndexedDB. A user of the application communicates with the Dart server by two buttons. The To server button sends local data to the server, while the From server button brings changes to the local data from the MongoDB database. ButtonElement toServer = querySelector('#to-server'); toServer.onClick.listen((MouseEvent e) { var request = new HttpRequest(); request.onReadyStateChange.listen((_) { if (request.readyState == HttpRequest.DONE && request.status == 200) { serverResponse = 'Server: ' + request.responseText; } else if (request.readyState == HttpRequest.DONE && request.status == 0) { // Status is 0...most likely the server isn't running. serverResponse = 'No server'; } }); var url = 'http://127.0.0.1:8080'; request.open('POST', url); request.send(_tasksStore.tasks.toJsonString()); }); ButtonElement fromServer = querySelector('#from-server'); fromServer.onClick.listen((MouseEvent e) { var request = new HttpRequest(); request.onReadyStateChange.listen((_) { if (request.readyState == HttpRequest.DONE && request.status == 200) { String jsonString = request.responseText; serverResponse = 'Server: ' + request.responseText; if (jsonString != '') { List<Map> jsonList = JSON.decode(jsonString); print('JSON list from the server: ${jsonList}'); _tasksStore.loadDataFromServer(jsonList) .then((_) { var tasks = _tasksStore.tasks; _clearElements(); loadElements(tasks); }) .catchError((e) { print('error in loading data into IndexedDB from JSON list'); }); } } else if (request.readyState == HttpRequest.DONE && request.status == 0) { // Status is 0...most likely the server isn't running. serverResponse = 'No server'; } }); var url = 'http://127.0.0.1:8080'; request.open('GET', url); request.send('update-me'); });> Server data are loaded in the loadDataFromServer method of the TasksStore class in todo_mongodb/todo_client_idb/lib/model/idb.dart. Future loadDataFromServer(List<Map> jsonList) { Completer completer = new Completer(); Tasks integratedTasks = _integrateDataFromServer(jsonList); clear() .then((_) { int count = 0; for (Task task in integratedTasks) { addTask(task) .then((_) { if (++count == integratedTasks.length) { completer.complete(); } }); } }); return completer.future; } The server data are integrated into the local data by the _integrateDataFromServer method of the TasksStore class. Tasks _integrateDataFromServer(List<Map> jsonList) { var serverTasks = new Tasks.fromJson(jsonList); var clientTasks = tasks.copy(); var clientTaskList = clientTasks.toList(); for (var clientTask in clientTaskList) { if (!serverTasks.contains(clientTask.title)) { clientTasks.remove(clientTask); } } for (var serverTask in serverTasks) { if (clientTasks.contains(serverTask.title)) { var clientTask = clientTasks.find(serverTask.title); clientTask.completed = serverTask.completed; clientTask.updated = serverTask.updated; } else { clientTasks.add(serverTask); } } return clientTasks; } Summary The TodoMVC client-server application is developed in Dart. The web application is done in DOM with local data from a simple model stored in an IndexedDB database. The local data are sent to the server as a JSON document. Data from the server are received also as a JSON document. Both on a client and on the server, data are integrated in the model. The server uses the Dartling domain framework for its model. The model is stored in the MongoDB database. The action events from Dartling are used to propagate changes from the model to the database. Resources for Article: Further resources on this subject: HTML5: Generic Containers [article] HTML5: Getting Started with Paths and Text [article] HTML5 Presentations - creating our initial presentation [article]
Read more
  • 0
  • 0
  • 5472

article-image-fundamentals
Packt
20 Jan 2014
4 min read
Save for later

Fundamentals

Packt
20 Jan 2014
4 min read
(For more resources related to this topic, see here.) Vulnerability Assessment and Penetration Testing Vulnerability Assessment ( VA) and Penetrating Testing ( PT or PenTest ) are the most common types of technical security risk assessments or technical audits conducted using different tools. These tools provide best outcomes if they are used optimally. An improper configuration may lead to multiple false positives that may or may not reflect true vulnerabilities. Vulnerability assessment tools are widely used by all, from small organizations to large enterprises, to assess their security status. This helps them with making timely decisions to protect themselves from these vulnerabilities. Vulnerability Assessments and PenTests using Nessus. Nessus is a widely recognized tool for such purposes. This section introduces you to basic terminology with reference to these two types of assessments. Vulnerability in terms of IT systems can be defined as potential weaknesses in system/infrastructure that, if exploited, can result in the realization of an attack on the system. An example of a vulnerability is a weak, dictionary-word password in a system that can be exploited by a brute force attack (dictionary attack) attempting to guess the password. This may result in the password being compromised and an unauthorized person gaining access to the system. Vulnerability Assessment is a phase-wise approach to identifying the vulnerabilities existing in an infrastructure. This can be done using automated scanning tools such as Nessus, which uses its set of plugins corresponding to different types of known security loopholes in infrastructure, or a manual checklist-based approach that uses best practices and published vulnerabilities on well-known vulnerability tracking sites. The manual approach is not as comprehensive as a tool-based approach and will be more time-consuming. The kind of checks that are performed by a vulnerability assessment tool can also be done manually, but this will take a lot more time than an automated tool. Penetration Testing has an additional step for vulnerability assessment, exploiting the vulnerabilities. Penetration Testing is an intrusive test, where the personnel doing the penetration test will first do a vulnerability assessment to identify the vulnerabilities, and as a next step, will try to penetrate the system by exploiting the identified vulnerabilities. Need for Vulnerability Assessment It is very important for you to understand why Vulnerability Assessment or Penetration Testing is required. Though there are multiple direct or indirect benefits for conducting a vulnerability assessment or a PenTest, a few of them have been recorded here for your understanding. Risk prevention Vulnerability Assessment uncovers the loopholes/gaps/vulnerabilities in the system. By running these scans on a periodic basis, an organization can identify known vulnerabilities in the IT infrastructure in time. Vulnerability Assessment reduces the likelihood of noncompliance to the different compliance and regulatory requirements since you know your vulnerabilities already. Awareness of such vulnerabilities in time can help an organization to fi x them and mitigate the risks involved in advance before they get exploited. The risks of getting a vulnerability exploited include: Financial loss due to vulnerability exploits Organization reputation Data theft Confidentiality compromise Integrity compromise Availability compromise Compliance requirements The well-known information security standards (for example, ISO 27001, PCI DSS, and PA DSS) have control requirements that mandate that a Vulnerability Assessment must be performed. A few countries have specific regulatory requirements for conducting Vulnerability Assessments in some specific industry sectors such as banking and telecom. The life cycles of Vulnerability Assessment and Penetration Testing This section describes the key phases in the life cycles of VA and PenTest. These life cycles are almost identical; Penetration Testing involves the additional step of exploiting the identified vulnerabilities. It is recommended that you perform testing based on the requirements and business objectives of testing in an organization, be it Vulnerability Assessment or Penetration Testing. The following stages are involved in this life cycle: Scoping Information gathering Vulnerability scanning False positive analysis Vulnerability exploitation (Penetration Testing) Report generation The following figure illustrates the different sequential stages recommended to follow for a Vulnerability Assessment or Penetration Testing: Summary In this article, we covered an introduction to Vulnerability Assessment and Penetration Testing, along with an introduction to Nessus as a tool and steps on installing and setting up Nessus. Resources for Article: Further resources on this subject: CISSP: Vulnerability and Penetration Testing for Access Control [Article] Penetration Testing and Setup [Article] Web app penetration testing in Kali [Article]
Read more
  • 0
  • 0
  • 14737

article-image-article-what_is_ngui
Packt
20 Jan 2014
8 min read
Save for later

What is NGUI?

Packt
20 Jan 2014
8 min read
(For more resources related to this topic, see here.) The Next-Gen User Interface kit is a plugin for Unity 3D. It has the great advantage of being easy to use, very powerful, and optimized compared to Unity's built-in GUI system, UnityGUI. Since it is written in C#, it is easily understandable and you may tweak it or add your own features, if necessary. The NGUI Standard License costs $95. With this, you will have useful example scenes included. I recommend this license to start comfortably—a free evaluation version is available, but it is limited, outdated, and not recommended. The NGUI Professional License, priced at $200, gives you access to NGUI's GIT repository to access the latest beta features and releases in advance. A $2000 Site License is available for an unlimited number of developers within the same studio. Let's have an overview of the main features of this plugin and see how they work. UnityGUI versus NGUI With Unity's GUI, you must create the entire UI in code by adding lines that display labels, textures, or any other UI element on the screen. These lines have to be written inside a special function, OnGUI(), that is called for every frame. This is no longer necessary; with NGUI, UI elements are simple GameObjects! You can create widgets—this is what NGUI calls labels, sprites, input fields, and so on—move them, rotate them, and change their dimensions using handles or the Inspector. Copying, pasting, creating prefabs, and every other useful feature of Unity's workflow is also available. These widgets are viewed by a camera and rendered on a layer that you can specify. Most of the parameters are accessible through Unity's Inspector, and you can see what your UI looks like directly in the Game window, without having to hit the Play button. Atlases Sprites and fonts are all contained in a large texture called atlas. With only a few clicks, you can easily create and edit your atlases. If you don't have any images to create your own UI assets, simple default atlases come with the plugin. That system means that for a complex UI window composed of different textures and fonts, the same material and texture will be used when rendering. This results in only one draw call for the entire window. This, along with other optimizations, makes NGUI the perfect tool to work on mobile platforms. Events NGUI also comes with an easy-to-use event framework that is written in C#. The plugin comes with a large number of additional components that you can attach to GameObjects. These components can perform advanced tasks depending on which events are triggered: hover, click, input, and so on. Therefore, you may enhance your UI experience while keeping it simple to configure. Code less, get more! Localization NGUI comes with its own localization system, enabling you to easily set up and change your UI's language with the push of a button. All your strings are located in the .txt files: one file per language. Shaders Lighting, normal mapping, and refraction shaders are supported in NGUI, which can give you beautiful results. Clipping is also a shader-controlled feature with NGUI, used for showing or hiding specific areas of your UI. We've now covered what NGUI's main features are, and how it can be useful to us as a plugin, and now it's time to import it inside Unity. Importing NGUI After buying the product from the Asset Store or getting the evaluation version, you have to download it. Perform the following steps to do so: Create a new Unity project. Navigate to Window | Asset Store. Select your downloads library. Click on the Download button next to NGUI: Next-Gen UI. When the download completes, click on the NGUI icon / product name in the library to access the product page. Click on the Import button and wait for a pop-up window to appear. Check the checkbox for NGUI v.3.0.2.unity package and click on Import. In the Project view, navigate to Assets | NGUI and double-click on NGUI v.3.0.2. A new imported pop-up window will appear. Click on Import again. Click any button on the toolbar to refresh it.The NGUI tray will appear! The NGUI tray will look like the following screenshot: You have now successfully imported NGUI to your project. Let's create your first 2D UI. Creating your UI We will now create our first 2D user interface with NGUI's UI Wizard. This wizard will add all the elements needed for NGUI to work. Before we continue, please save your scene as Menu.unity. UI Wizard Create your UI by opening the UI Wizard by navigating to NGUI | Open | UIWizard from the toolbar. Let's now take a look at the UI Wizard window and its parameters. Window You should now have the following pop-up window with two parameters: Parameters The two parameters are as follows: Layer: This is the layer on which your UI will be displayed Camera: This will decide if the UI will have a camera, and its drop-down options are as follows: None: No camera will be created Simple 2D:Uses a camera with orthographic projection Advanced 3D:Uses a camera with perspective projection Separate UI Layer I recommend that you separate your UI from other usual layers. We should do it as shown in the following steps: Click on the drop-down menu next to the Layer parameter. Select Add Layer. Create a new layer and name it GUI2D. Go back to the UI Wizard window and select this new GUI2D layer for your UI. You can now click on the Create Your UI button. Your first 2D UI has been created! Your UI structure The wizard has created four new GameObjects on the scene for us: UI Root (2D) Camera Anchor Panel Let's now review each in detail. UI Root (2D) The UIRoot component scales widgets down to keep them at a manageable size. It is also responsible for the Scaling Style—it will either scale UI elements to remain pixel perfect or to occupy the same percentage of the screen, depending on the parameters you specify. Select the UI Root (2D) GameObject in the Hierarchy. It has the UIRoot.cs script attached to it. This script adjusts the scale of the GameObject it's attached to in order to let you specify widget coordinates in pixels, instead of Unity units as shown in the following screenshot: Parameters The UIRoot component has four parameters: Scaling Style: The following are the available scaling styles: PixelPerfect:This will ensure that your UI will always try to remain at the same size in pixels, no matter what resolution. In this scaling mode, a 300 x 200 window will be huge on a 320 x 240 screen and tiny on a 1920 x 1080 screen. That also means that if you have a smaller resolution than your UI, it will be cropped. FixedSize:This will ensure that your UI will be proportionally resized depending on the screen's height. The result is that your UI will not be pixel perfect but will scale to fit the current screen size. FixedSizeOnMobiles:This will ensure fixed size on mobiles and pixel perfect everywhere else. Manual Height: With the FixedSize scaling style, the scale will be based on this height. If your screen's height goes over or under this value, it will be resized to be displayed identically while maintaining the aspect ratio(width/height proportional relationship). Minimum Height: With the PixelPerfect scaling style, this parameter defines the minimum height for the screen. If your screen height goes below this value, your UI will resize. It will be as if the Scaling Style parameter was set to FixedSize with Manual Height set to this value. Maximum Height: With the PixelPerfect scaling style, this parameter defines the maximum height for the screen. If your screen height goes over this value,your UI will resize. It will be as if the ScalingStyle parameter was set to FixedSize with Manual Height set to this value. Please set the Scaling Style parameter to FixedSize with a Manual Height value of 1080. This will allow us to have the same UI on any screen size up to 1920 x 1080. Even though the UI will look the same on different resolutions, the aspect ratio is still a problem since the rescale is based on the screen's height only. If you want to cover both 4:3 and 16:9 screens, your UI should not be too large—try to keep it square.Otherwise, your UI might be cropped on certain screen resolutions. On the other hand, if you want a 16:9 UI, I recommend you force this aspect ratio only. Let's do it now for this project by performing the following steps: Navigate to Edit| Project Settings | Player. In the Inspectoroption, unfold the Resolution and Presentationgroup. Unfold the Supported Aspect Ratios group. Check only the 16:9 box. Summary In this article, we discussed NGUI's basic workflow—it works with GameObjects, uses atlases to combine multiple textures in one large texture, has an event system, can use shaders, and has a localization system. After importing the NGUI plugin, we created our first 2D UI with the UI Wizard, reviewed its parameters, and created our own GUI 2D layer for our UI to reside on. Resources for Article: Further resources on this subject: Unity 3D Game Development: Don't Be a Clock Blocker [Article] Component-based approach of Unity [Article] Unity 3: Building a Rocket Launcher [Article]
Read more
  • 0
  • 0
  • 11613
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-server-logs
Packt
20 Jan 2014
9 min read
Save for later

Server Logs

Packt
20 Jan 2014
9 min read
(For more resources related to this topic, see here.) Monitoring a live system is crucial to maintaining stability and performance; not only to avoid potential failures but even for debugging and tracing back an event. That is why having a system record its activities results in a rich database of logs that can be used for investigation. Logfiles tell a fascinating story to those who can read it. They carry the history of all events narrated in thorough detail. ArcGIS for Server, like any other system, keeps logfiles for all events, from the basic "connection established" event to the severe "service failed to initiate" event. Logging levels Recording events on Server is done at different levels. You can tell Server to log every single event as it happens or filter to record only fatal errors. Consequently, recording fine events generates more logs than recording only those messages with errors. There are seven logging levels, and these are described in the following Esri table: Log level Description Severe This level logs serious problems that require immediate attention. It only includes severe messages. Warning This level logs moderate problems that require attention. It also includes severe-level messages. Info This level logs common administrative messages from Server, including messages about service creation and startup. It also includes severe and warning messages. Fine This level logs common messages from users of Server, such as names of operation requests received. It includes severe, warning, and info messages. Verbose This level logs messages providing more details about how Server completes an operation, such as whether each layer in a map service was drawn successfully, how fast the layer was drawn, and how long it took Server to access the layer's source data. This level includes severe, warning, info, and fine messages. Debug This level logs highly verbose messages designed for developers and support technicians who want to obtain a better understanding of the state of Server when troubleshooting. This level should not be used in a production environment as it may cause a significant decrease in Server performance. Off At this level, logging is turned off. Events are not logged with Server. As you can see, Debug is the finest level and keeps Server busy with logging events, making other important tasks suffer. Log analysis Logs can be viewed and refreshed actively from the ArcGIS for Server Manager window as they are written. To see your current logfiles, go to Manager and activate the Logs tab: Naturally, each GIS server generates its own logs and this is all saved by default at C:arcgisserverlogs. You cannot use a shared folder for this; each GIS server should generate its own logs in its directory, ArcGIS for Server aggregates those logs into the Server site, in a table view with filters options, which allows you to search through the logs. From the View Log Messages panel, click on Query to view the current logfiles as shown in the following screenshot. You might get messages different from mine. You might not have any messages if your current log level is set to only record errors, and there are no errors. To change the log level, click on Settings. From the Log Settings form, select Verbose from the Log Level drop-down list. You can set the logs to be cleared automatically if you want to. Keep the rest of the settings intact and click on the Save button. By default, the logs are kept on the GIS server for three months. If you are planning to keep the logs for longer than that, perhaps for offline analysis, you may want to archive them periodically and delete them. Generally, clearing the logs is better for performance. This will be discussed in the coming pages. Best practice Since logs are saved to disk frequently, they use high IO. It is recommended that you point the log path to a local directory, preferably on a Solid State Drive (SSD) for best performance. Now, let us see how the logs are being generated. First of all, let us clear all the logs to start afresh. To do that, click on Delete Logs from ArcGIS for Server Manager and then click on Yes, as shown in the following screenshot: Now that the logs are cleared, we will activate the parcels service by simply visiting the REST URL and then checking the log. Type the REST URL on a new browser page and press Enter. You should see something like the following screenshot if you have access to the service: Go back to your logs and click on Query to refresh the page. You should see one message in the table. You might see other messages from Server that happened to be executed at that particular time but look for this one: Level Time Message Source Machine User Name INFO Nov 17, 2013, 11:18:26 AM Request user: Anonymous user, Service: Parcels/MapServer Rest GIS-SERVER01 Anonymous user The level is INFO, which means a detailed event; it says a request user from REST consumed the Parcels Map Service and GIS-SERVER01 served that request. If you have security enabled, you would even know which user consumed that service. Now, let us take it to the next level. On the Parcels REST page, click on ArcGIS JavaScript to view the map with the service loaded. Go back to the log view and click on Query to refresh; make sure the Log Filter dropdown is set to Verbose. A fleet of messages was generated from our last action; we will take a look at each line and analyze it. There are many columns that can be displayed on the log table and you can show or hide them from the Columns button. For a better view, you can click on the Printer Friendly View link, which will display a text format version of this table in a new page. This is the log we are going to analyze; we will start from the first line: INFO, Nov 17, 2013, 11:29:17 AM, Request user: Anonymous user, Service: Parcels/MapServer Rest. This is a request to consume the service. You can use this identifier to measure how many times a service has been requested. FINE Nov 17, 2013, 11:29:17 AM REST request received. Request size is 178 characters. Parcels.MapServer The preceding line is appended if there is more work to be followed; it shows the request size in bytes. FINE Nov 17, 2013, 11:29:17 AM Begin ExportMapImage Parcels.MapServer The process is so fast that we are still in the same second. The preceding line of code tells us that the Export Map Image process just started. This is the big process where Server exports an image of the desired area; however, there is still more work to follow to create the actual image. You can start measuring the drawing time of a certain service from this line. VERBOSE Nov 17, 2013, 11:29:17 AM Begining of preparation. Parcels.MapServer VERBOSE Nov 17, 2013, 11:29:17 AM End of preparation. Parcels.MapServer The preceding two lines highlight the preparation of the export image process. They usually happen very fast. FINE Nov 17, 2013, 11:29:17 AM Extent:1467314.863829,2191233.084700,2574598.328396,2702665.79038; Size:1574,727; Scale:2658831.00Parcels.MapServer A map needs an initial extent coordinates for it to draw. At the first call of the service, Server implicitly sends the default full extent to draw the map. After that, the user will explicitly request a new extent, each time he/she zooms in or pans the map. VERBOSE Nov 17, 2013, 11:29:17 AM Beginning of layer draw: Parcels Parcels.MapServer Since we only have one layer, you will see one occurrence of this line; however, you will see these lines reappear with more layers and there will be more logs to follow. VERBOSE Nov 17, 2013, 11:29:17 AM Execute Query Parcels.MapServer I consider this one of the most important lines; this is where the database is advised and queried to get the actual features. You can make a good measurement here by monitoring how long an execute query takes. If this takes a long time to execute, you might want to consult your DBA to look into tuning the database. VERBOSE Nov 17, 2013, 11:29:17 AM Symbol Drawing Parcels.MapServer VERBOSE Nov 17, 2013, 11:29:17 AM Data Access Parcels.MapServer VERBOSE Nov 17, 2013, 11:29:17 AM Symbolizing Parcels.MapServer Symbology work, depending on the user, can be executed either on the server or on the client. Since we are running on a browser, the symbology drawing will be carried on the client's browser by JavaScript. Note that this is only the symbology drawing; the labeling is done in another step. VERBOSE Nov 17, 2013, 11:29:17 AM Number of features drawn: 10 Parcels.MapServer This message shows the number of features that have been drawn. This line is useful if you want to know how many features are retrieved for each request and monitor the performance. VERBOSE Nov 17, 2013, 11:29:17 AM End of layer draw: Parcels Parcels.MapServer This line signifies the end of layer drawing; you should now start seeing the map, but with no labels. VERBOSE Nov 17, 2013, 11:29:17 AM Beginning of labeling phase (labeling and label draw) Parcels.MapServer Now that the symbology work is done, the labeling will start. This will give you even more measurement indicators for performance. VERBOSE Nov 17, 2013, 11:29:17 AM Symbol Drawing Parcels.MapServer It draws the font symbol as described in the layer description which can be found in the layer properties. VERBOSE Nov 17, 2013, 11:29:17 AM Number of features drawn: 10 Parcels.MapServer The preceding line indicates that the features have been labeled successfully. VERBOSE Nov 17, 2013, 11:29:17 AM End of labeling phase (labeling and label draw) Parcels.MapServer The preceding line marks the end of the labeling phase. FINE Nov 17, 2013, 11:29:17 AM End ExportMapImage Parcels.MapServer The map image has been exported successfully; we will attempt to deliver it to the client after this. FINE Nov 17, 2013, 11:29:17 AM REST request successfully processed. Response size is 6364 characters. Parcels.MapServer The last message describes the response map, which is a 6K map image. My Server is so fast that the whole thing happened in the same second. This is not much by way of a log analysis. However, in the next topic we will attempt to analyze a much richer log and will try to answer some questions.
Read more
  • 0
  • 0
  • 3176

article-image-grunt-action
Packt
20 Jan 2014
5 min read
Save for later

Grunt in Action

Packt
20 Jan 2014
5 min read
(For more resources related to this topic, see here.) Step 4 – optimizing our build files At this point, we should have a structured set of source files and can now perform additional transformations on the result. Let's start by downloading the plugins from npm and saving them in our package.json file: $ npm install --save-dev grunt-contrib-uglify grunt-contrib-cssmin grunt-contrib-htmlmin Then, at the top of our Gruntfile.js file, where we have loaded our other Grunt plugins, we will load our new additions with: grunt.loadNpmTasks("grunt-contrib-uglify"); grunt.loadNpmTasks("grunt-contrib-cssmin"); grunt.loadNpmTasks("grunt-contrib-htmlmin"); Scripts We will start by compressing our scripts. In this example, we use the grunt-contrib-uglify plugin http://gswg.io#grunt-contrib-uglify), which is a wrapper around the popular UglifyJS library (http://gswg.io#uglifyjs). Now we have loaded the plugin, which provides the uglify task, we just need to configure it: uglify: { compress: { src: "<%= coffee.build.dest %>", dest: "<%= coffee.build.dest %>" } } Here, inside the uglify property, we have made a compress target, which has src and dest set to the same file. Instead of entering the actual filename, we are making use of Grunt templates to retrieve the value at the given configuration path (coffee.build.dest), which in this case, resolves to build/js/app.js. Grunt templates make it easy to have a single source of truth within our configuration. Therefore, if we ever want to change the file path of our JavaScript, we only need to change one configuration entry. Since we have set the source and destination to the same file path, in effect, we are overwriting our JavaScript with the compressed version of itself. However, if we were writing a JavaScript library instead of a web application, we'd most likely want to compress our app.js file into an app.min.js file, so its users could download an uncompressed and a compressed version. Running this uglify task with this basic configuration should result in the following app.js file: (function(){var a,b;a=function(a,b){return a+b},b=function(a,b){return a-b},alert(a(7,b(4,1)))}).call(this); Generally, this will suffice, however, UglifyJS also offers advanced features. For example, in some cases, we might have portions of code that are only used during development. We could remove this unnecessary code with the following technique. By defining a DEBUG variable and place our debug-related code inside an if block as follows: if(DEBUG) { //do things here } Then, if we used the following options object inside our uglify configuration as follows: options: { compress: { global_defs: { "DEBUG": false }, dead_code: true } } This would result in UglifyJS locking the value of DEBUG to false and also to remove the inaccessible code (dead code). Therefore, in addition to compressing code, we also have the ability to completely remove code from our builds. The documentation for this feature can be found at http://gswg.io#grunt-contrib-uglify-conditional-compilation. Styles To compress our styles, we use the grunt-contrib-cssmin plugin (http://gswg.io#grunt-contrib-cssmin), which is a wrapper around the clean-css library (http://gswg.io#clean-css). Since we have installed this plugin, we just need to include the cssmin task configuration: cssmin: { compress: { src: "<%= stylus.build.dest %>", dest: "<%= stylus.build.dest %>" } } Similar to our scripts configuration, we can see that the only real difference is that we point to the stylus task's output instead of pointing to the coffee task's output. When we run grunt cssmin, our css/app.css file should be modified to the following one: html,body{margin:0;padding:0}.content .middle{font-size:16pt}@media (max-width:768px){.content .middle{font-size:8pt}} Views Finally, to compress our views, we will use the grunt-contrib-htmlmin plugin (http://gswg.io#grunt-contrib-htmlmin), which is a wrapper around the html-minifier library (http://gswg.io#html-minifier). The htmlmin configuration has a little more to it: since its compression options are disabled by default, we need to enable the rules we wish to use: htmlmin: { options: { removeComments: true, collapseWhitespace: true, collapseBooleanAttributes: true, removeAttributeQuotes: true, removeRedundantAttributes: true, removeOptionalTags: true }, compress: { src: "<%= jade.build.dest %>", dest: "<%= jade.build.dest %>" } } Now our htmlmin task is configured, we can run it with grunt htmlmin, which should modify our build/app.html to the following: <!DOCTYPE html><html><head><link rel=stylesheet href=css/app. css><body><section class=header>this is the <b>amazing</b> header section</section><section class=content><div class=top>some content with this on top</div><div class=middle>and this in the middle</ div><div class=bottom>and this on the bottom</div></section><section class=footer>and this is the footer, with an awesome copyright symbol with the year next to it - © 2013</section><script src = js/app. js></script> In addition to the GitHub repository, we can read more about html-minifier on Juriy "Kangax" Zaytsev's blog at http://gswg.io#experimenting-with-html-minifier. Summary In this article we performed additional transformations on set of source files by using Grunt. Resources for Article: Further resources on this subject: Trapping Errors by Using Built-In Objects in JavaScript Testing [article] Developing Wiki Seek Widget Using Javascript [article] Working with JavaScript in Drupal 6: Part 1 [article]
Read more
  • 0
  • 0
  • 1623

article-image-intents-mobile-components
Packt
20 Jan 2014
7 min read
Save for later

Intents for Mobile Components

Packt
20 Jan 2014
7 min read
(For more resources related to this topic, see here.) Common mobile components Due to the open source nature of the Android operating system, many different companies such as HTC and Samsung ported the Android OS on their devices with many different functionalities and styles. Each Android phone is unique in some way or the other and possesses many unique features and components different from other brands and phones. But there are some components that are found to be common in all the Android phones. We are using two key terms here: components and features. Component is the hardware part of an Android phone, such as camera, Bluetooth and so on. And Feature is the software part of an Android phone, such as the SMS feature, E-mail feature, and so on. This article is all about hardware components, their access, and their use through intents. These common components can be generally used and implemented independently of any mobile phone or model. And there is no doubt that intents are the best asynchronous messages to activate these Android components. These intents are used to trigger the Android OS when some event occurrs and some action should be taken. Android, on the basis of the data received, determines the receiver for the intent and triggers it. Here are a few common components found in each Android phone: The Wi-Fi component Each Android phone comes with a complete support of the Wi-Fi connectivity component. The new Android phones having Android Version 4.1 and above support the Wi-Fi Direct feature as well. This allows the user to connect to nearby devices without the need to connect with a hotspot or network access point. The Bluetooth component An Android phone includes Bluetooth network support that allows the users of Android phones to exchange data wirelessly in low range with other devices. The Android application framework provides developers with the access to Bluetooth functionality through Android Bluetooth APIs. The Cellular component No mobile phone is complete without a cellular component. Each Android phone has a cellular component for mobile communication through SMS, calls, and so on. The Android system provides very high, flexible APIs to utilize telephony and cellular components to create very interesting and innovative apps. Global Positioning System (GPS) and geo-location GPS is a very useful but battery-consuming component in any Android phone. It is used for developing location-based apps for Android users. Google Maps is the best feature related to GPS and geo-location. Developers have provided so many innovative apps and games utilizing Google Maps and GPS components in Android. The Geomagnetic field component Geomagnetic field component is found in most Android phones. This component is used to estimate the magnetic field of an Android phone at a given point on the Earth and, in particular, to compute magnetic declination from the North. The geomagnetic field component uses the World Magnetic Model produced by United States National Geospatial-Intelligence Agency. The current model that is being used for the geomagnetic field is valid until 2015. Newer Android phones will have the newer version of the geomagnetic field. Sensor components Most Android devices have built-in sensors that measure motion, orientation, environment conditions, and so on. These sensors sometimes act as the brains of the app. For example, they take actions on the basis of the mobile's surrounding (weather) and allow users to have an automatic interaction with the app. These sensors provide raw data with high precision and accuracy for measuring the respective sensor values. For example, gravity sensor can be used to track gestures and motions, such as tilt, shake, and so on, in any app or game. Similarly, a temperature sensor can be used to detect the mobile temperature, or a geomagnetic sensor (as introduced in the previous section) can be used in any travel application to track the compass bearing. Broadly, there are three categories of sensors in Android: motion, position, and environmental sensors. The following subsections discuss these types of sensors briefly. Motion sensors Motion sensors let the Android user monitor the motion of the device. There are both hardware-based sensors such as accelerometer, gyroscope, and software-based sensors such as gravity, linear acceleration, and rotation vector sensors. Motion sensors are used to detect a device's motion including tilt effect, shake effect, rotation, swing, and so on. If used properly, these effects can make any app or game very interesting and flexible, and can prove to provide a great user experience. Position sensors The two position sensors, geomagnetic sensor and orientation sensor, are used to determine the position of the mobile device. Another sensor, the proximity sensor, lets the user determine how close the face of a device is to an object. For example, when we get any call on an Android phone, placing the phone on the ear shuts off the screen, and when we hold the phone back in our hands, the screen display appears automatically. This simple application uses the proximity sensor to detect the ear (object) with the face of the device (the screen). Environmental sensors These sensors are not used much in Android apps, but used widely by the Android system to detect a lot of little things. For example, the temperature sensor is used to detect the temperature of the phone, and can be used in saving the battery and mobile life. At the time of writing this article, the Samsung Galaxy S4 Android phone has been launched. The phone has shown a great use of environmental gestures by allowing users to perform actions such as making calls by no-touch gestures such as moving your hand or face in front of the phone. Components and intents Android phones contain a large number of components and features. This becomes beneficial to both Android developers and users. Android developers can use these mobile components and features to customize the user experience. For most components, developers get two options; either they extend the components and customize those according to their application requirements, or they use the built-in interfaces provided by the Android system. We won't read about the first choice of extending components as it is beyond the scope of this article. However, we will study the other option of using built-in interfaces for mobile components. Generally, to use any mobile component from our Android app, the developers send intents to the Android system and then Android takes the action accordingly to call the respective component. Intents are asynchronous messages sent to the Android OS to perform any functionality. Most of the mobile components can be triggered by intents just by using a few lines of code and can be utilized fully by developers in their apps. In the following sections of this article, we will see few components and how they are used and triggered by intents with practical examples. We have divided the components in three ways: communication components, media components, and motion components. Now, let's discuss these components in the following sections. Communication components Any mobile phone's core purpose is communication. Android phones provide a lot of features other than communication features. Android phones contain SMS/MMS, Wi-Fi, and Bluetooth for communication purposes. This article focuses on the hardware components; so, we will discuss only Wi-Fi and Bluetooth. The Android system provides built-in APIs to manage and use Bluetooth devices, settings, discoverability, and much more. It offers full network APIs not only for Bluetooth but also for Wi-Fi, hotspots, configuring settings, Internet connectivity, and much more. More importantly, these APIs and components can be used very easily by writing few lines of code through intents. We will start by discussing Bluetooth, and how we can use Bluetooth through intents in the next section.
Read more
  • 0
  • 0
  • 4591

article-image-using-phalcon-models-views-and-controllers
Packt
20 Jan 2014
3 min read
Save for later

Using Phalcon Models, Views, and Controllers

Packt
20 Jan 2014
3 min read
(For more resources related to this topic, see here.) Creating CRUD scaffolding CRUD stands for create, read, update, and delete, which are the four basic functions our application should do with our blog post records. Phalcon web tools will also help us to get these built. Click on the Scaffold tab on the web tools page and you will see a page as shown in the following screenshot: Select posts from the Table name list and volt from the Template engine list, and check Force this time, because we are going to force our new files to overwrite the old model and controller files that we just generated. Click on the Generate button and some magic should happen. Browse to http://localhost/phalconBlog/posts and you will see a page like the following screenshot: We finally have some functionality we can use. We have no posts, but we can create some. Click on the Create posts link and you will see a page similar to the one we were just at. The form will look nearly the same, but it will have a Create posts heading. Fill out the Title, Body, and Excerpt fields and click on the Save button. The form will post, and you will get a message stating that the post was created successfully. This will take you back to the post's index page. Now you should be able to search for and find the post you just created. If you forgot what you posted, you can click on Search without entering anything in the fields, and you should see a page like the following screenshot: This is not a very pretty or user-friendly blog application. But it got us started, and that's all we need. The next time we start a Phalcon project, it should only take a few minutes to go through these steps. Now we will look over our generated code, and as we do, modify it to make it more blog-like. Summary In this article, we worked on the model, view, and controller for the posts in our blog. To do this, we used Phalcon web tools to generate our CRUD scaffolding for us. Then, we modified this generated code so it would do what we need it to do. We can now add posts. We also learned about the Volt template engine. Resources for Article: Further resources on this subject: Using An Object Oriented Approach for Implementing PHP Classes to Interact with Oracle [Article] FuelPHP [Article] Installing PHP-Nuke [Article]
Read more
  • 0
  • 0
  • 2996
article-image-search-using-beautiful-soup
Packt
20 Jan 2014
6 min read
Save for later

Search Using Beautiful Soup

Packt
20 Jan 2014
6 min read
(For more resources related to this topic, see here.) Searching with find_all() The find() method was used to find the first result within a particular search criteria that we applied on a BeautifulSoup object. As the name implies, find_all() will give us all the items matching the search criteria we defined. The different filters that we see in find() can be used in the find_all() method. In fact, these filters can be used in any searching methods, such as find_parents() and find_siblings(). Let us consider an example of using find_all(). Finding all tertiary consumers We saw how to find the first and second primary consumer. If we need to find all the tertiary consumers, we can't use find(). In this case, find_all() will become handy. all_tertiaryconsumers = soup.find_all(class_="tertiaryconsumerslist") The preceding code line finds all the tags with the = "tertiaryconsumerlist" class. If given a type check on this variable, we can see that it is nothing but a list of tag objects as follows: print(type(all_tertiaryconsumers)) #output <class 'list'> We can iterate through this list to display all tertiary consumer names by using the following code: for tertiaryconsumer in all_tertiaryconsumers: print(tertiaryconsumer.div.string) #output lion tiger Understanding parameters used with find_all() Like find(), the find_all() method also has a similar set of parameters with an extra parameter, limit, as shown in the following code line: find_all(name,attrs,recursive,text,limit,**kwargs) The limit parameter is used to specify a limit to the number of results that we get. For example, from the e-mail ID sample we saw, we can use find_all() to get all the e-mail IDs. Refer to the following code: email_ids = soup.find_all(text=emailid_regexp) print(email_ids) #output [u'abc@example.com',u'xyz@example.com',u'foo@example.com'] Here, if we pass limit, it will limit the result set to the limit we impose, as shown in the following example: email_ids_limited = soup.find_all(text=emailid_regexp,limit=2) print(email_ids_limited) #output [u'abc@example.com',u'xyz@example.com'] From the output, we can see that the result is limited to two. The find() method is find_all() with limit=1. We can pass True or False values to find the methods. If we pass True to find_all(), it will return all tags in the soup object. In the case of find(), it will be the first tag within the object. The print(soup.find_all(True)) line of code will print out all the tags associated with the soup object. In the case of searching for text, passing True will return all text within the document as follows: all_texts = soup.find_all(text=True) print(all_texts) #output [u'n', u'n', u'n', u'n', u'n', u'plants', u'n', u'100000', u'n', u'n', u'n', u'algae', u'n', u'100000', u'n', u'n', u'n', u'n', u'n', u'deer', u'n', u'1000', u'n', u'n', u'n', u'rabbit', u'n', u'2000', u'n', u'n', u'n', u'n', u'n', u'fox', u'n', u'100', u'n', u'n', u'n', u'bear', u'n', u'100', u'n', u'n', u'n', u'n', u'n', u'lion', u'n', u'80', u'n', u'n', u'n', u'tiger', u'n', u'50', u'n', u'n', u'n', u'n', u'n'] The preceding output prints every text content within the soup object including the new-line characters too. Also, in the case of text, we can pass a list of strings and find_all() will find every string defined in the list: all_texts_in_list = soup.find_all(text=["plants","algae"]) print(all_texts_in_list) #output [u'plants', u'algae'] This is same in the case of searching for the tags, attribute values of tag, custom attributes, and the CSS class. For finding all the div and li tags, we can use the following code line: div_li_tags = soup.find_all(["div","li"]) Similarly, for finding tags with the producerlist and primaryconsumerlist classes, we can use the following code lines: all_css_class = soup.find_all(class_=["producerlist","primaryconsumerlist"]) Both find() and find_all() search an object's descendants (that is, all children coming after it in the tree), their children, and so on. We can control this behavior by using the recursive parameter. If recursive = False, search happens only on an object's direct children. For example, in the following code, search happens only at direct children for div and li tags. Since the direct child of the soup object is html, the following code will give an empty list: div_li_tags = soup.find_all(["div","li"],recursive=False) print(div_li_tags) #output [] If find_all() can't find results, it will return an empty list, whereas find() returns None. Navigation using Beautiful Soup Navigation in Beautiful Soup is almost the same as the searching methods. In navigating, instead of methods, there are certain attributes that facilitate the navigation. So each Tag or NavigableString object will be a member of the resulting tree with the Beautiful Soup object placed at the top and other objects as the nodes of the tree. The following code snippet is an example for an HTML tree: html_markup = """<div class="ecopyramid"> <ul id="producers"> <li class="producerlist"> <div class="name">plants</div> <div class="number">100000</div> </li> <li class="producerlist"> <div class="name">algae</div> <div class="number">100000</div> </li> </ul> </div>""" For the previous code snippet, the following HTML tree is formed: In the previous figure, we can see that Beautiful Soup is the root of the tree, the Tag objects make up the different nodes of the tree, while NavigableString objects make up the leaves of the tree. Navigation in Beautiful Soup is intended to help us visit the nodes of this HTML/XML tree. From a particular node, it is possible to: Navigate down to the children Navigate up to the parent Navigate sideways to the siblings Navigate to the next and previous objects parsed We will be using the previous html_markup as an example to discuss the different navigations using Beautiful Soup. Summary In this article, we discussed in detail the different search methods in Beautiful Soup, namely, find(), find_all(), find_next(), and find_parents(); code examples for a scraper using search methods to get information from a website; and understanding the application of search methods in combination. We also discussed in detail the different navigation methods provided by Beautiful Soup, methods specific to navigating downwards and upwards, and sideways, to the previous and next elements of the HTML tree. Resources for Article: Further resources on this subject: Web Services Testing and soapUI [article] Web Scraping with Python [article] Plotting data using Matplotlib: Part 1 [article]
Read more
  • 0
  • 0
  • 8522

article-image-creating-basic-javascript-plugin
Packt
17 Jan 2014
9 min read
Save for later

Creating a basic JavaScript plugin

Packt
17 Jan 2014
9 min read
(For more resources related to this topic, see here.) Getting started with an empty plugin To get started, create three files called manifest.xml, MyCompany.WebAccess.Plugin.debug.js, and MyCompany.WebAccess.Plugin.min.js. In the manifest.xml file, place the following XML: <WebAccess version="12.0"> <plugin name="MyCompany Plugin - Web Access" vendor="Gordon Beeming" moreinfo="http://31og.com" version="1.0"> <modules> <module namespace="MyCompany.WebAccess.Plugin" loadAfter="TFS.Agile.TaskBoard.View"/> <module namespace="MyCompany.WebAccess.Plugin" loadAfter="TFS.Agile.Boards.Controls"/> </modules> </plugin> </WebAccess> In the preceding code, once the plugin node has the attributes name, vendor, moreinfo, and version, we will be able to easily identify our plugin in the TFS Web Access admin area. Under the modules node, you will see that we have added two child module nodes. This informs TFS that we want to load our MyCompany.WebAccess.Plugin namespace after the TFS.Agile.TaskBoard.View and TFS.Agile.Boards.Controls namespaces, which are namespaces loaded on the task board and portfolio boards. You can get the base of this plugin from the sample code in the MyCompany.WebAccess.Plugin - Base.js file. If you have used the RequireJs module loader, you will notice that this syntax is very familiar. In the base code, you will see a bit of code like the following: TfsWebAccessPlugin.prototype.initialize = function () { // place code here to get started alert('MyCompany.WebAccess.Plugin is running'); }; This initialize method is where you start gaining control of what is happening in Web Access. Take all the code in the base code and place it in the debug.js file. Importing a plugin into TFS Web Access The first part of importing a plugin into TFS is to make sure that you have placed a minified version of your *.debug.js contents into your *.min.js file. Update the version of your plugin in the manifest.xml file, if required; for now, we will leave it at 1.0. Zip the three files we created; the name of this ZIP file doesn't make a difference to the usage of the plugin. Browse to the server's home page and then click on the Administer Server button in the top-right corner as shown in the following screenshot: The Administer Server Button Click on the Extensions tab and then click on Install . In the model window, click on browse to browse for the ZIP file you created with the contents of the plugin and then click on OK . You will now see that the plugin is visible in the extensions screen but is currently not enabled. Click on Enable and then on OK to enable it, as shown in the following screenshot: Web access extension when disabled When you navigate to any of the boards, you will see the alert that we placed in the initialize function. Setting up the debug mode We have just imported our plugin into TFS, and this was quite a long process. Although it is fine if we upload our plugin into an environment, when we have finished creating our plugin, it becomes very time consuming when we need to make changes to the plugin. You have to go through this whole process to see the changes. So, we will use some tricks that will help us debug our extension. Enabling the Script Debug Mode Navigate to the TFS URL with _diagnostics appended at the end, that is, http://gordon-pc:8080/tfs/_diagnostics. On this page, we will click on the Script Debug Mode link, which should currently be disabled. This should also switch Client Trace Point Collector to Enabled , as shown in the following screenshot: TFS diagnostics settings This will now make TFS use the debug.js file instead of the min.js file. You will also see more requests for JavaScript files as each file is now streamed separately instead of being bundled together for better load performance. For this reason, it is probably very clear that this should not be enabled on a production environment. Configuring a Fiddler AutoResponder rule The next part is to configure Fiddler to automatically respond to any requests for your plugin from the server with your local debug.js file. You can download Fiddler from http://fiddler2.com/. We are going to use Fiddler to intercept the request for our plugins' JavaScript file from TFS and use our local version of the plugin. The first step would be to start up Fiddler and make sure you can see the request for the MyCompany.WebAccess.Plugin.js file, which should have a URL similar to http://gordon-pc:8080/tfs/_static/tfs/12/_scripts/TFS/debug//tfs/_plugins/1957/MyCompany.WebAccess.Plugin.js. In Fiddler, switch to the AutoResponder tab and check Enable automatic responses and Unmatched requests passthrough . Now click on Add Rule and in the Rule editor menu, use the regex:http://gordon-pc:8080/tfs/_static/tfs/12/_scripts/TFS/.+/MyCompany.WebAccess.Plugin.js rule; this will put a wildcard on the mode and plugin ID that is being used currently. In the second textbox, write down the full location of the debug.js file for this plugin and then click on Save . Add a second rule in the same pattern, but this time in the second textbox, use header:CachControl=no-cache and click on Save . You should see something similar to the following screenshot in Fiddler: Fiddler AutoResponder rule added This will now make Web Access use your local debug.js file for all requests for the plugin in TFS. To try this out, go to the debug.js file, change the alert to we have added debugging , and save the file. Refresh the board, and you will see that without any additional effort, the alert changed. Adding information to display work items We will be going through some of the snippets that make a difference and are crucial to our plugin working correctly. The easiest way to make use of these types of plugins is to change the HTML based on the information available in the HTML; this is useful for small changes, such as displaying the ID of work items on the work item cards on the boards. For this, you would, on initialization of your plugin, use the setInterval function in JavaScript and call the following function every 500 milliseconds: function TaskBoardFunctions() { //replace IDs for tasks $("#taskboard-table .tbTile").each(function () { var id = $(this).attr("id"); id = id.split('-')[1]; $(this).find(".tbTileContent .witTitle").html("<span style='font-weight:bold;'>" + id + "</span> - " + $(this).find(".witTitle").html()); }); //replace IDs for tasks $("#taskboard-table .taskboard-row .taskboard-parent").each(function () { var id = $(this).attr("id"); if (id != undefined) { id = id.split('_')[1]; id = id.substring(1); $(this).find(".witTitle").html("<span style='font-weight:bold;'>" + id + "</span> - " + $(this).find(".witTitle").html()); } }); } This function just looks for all work items on the page using the IDs that are specified in the attributes in the HTML elements to add the IDs to the UI. A better way to do this would be to make use of the events in the API, and only make modifications to the displayed information when necessary. You would still use something similar to the preceding code for your initial loading to go through the board, and set all the information you would want to display; however, you would reply on the events to do any further updates. So, in this case, we would use the preceding code to scan for all the IDs on the page and then pass that through to a method, such as the following one, which will query the work item store. TFS has a configurable value that tells us the number of results that can be returned per query through the JavaScript API, and for this reason, we query 100 work items at a time; however, you can change this if it's not applicable to your plugin. Core.prototype.loadWorkItemsWork = function (idsToFetch, onComplete, that) { var takeAmount = 100; if (takeAmount >= idsToFetch.length) { takeAmount = idsToFetch.length; } if (takeAmount > 0) { that.WorkItemManager.store.beginPageWorkItems(idsToFetch.splice(0,takeAmount), [ "System.Id", "System.State" ], function (payload) { that.loadWorkItemsWork(idsToFetch, onComplete, that); $.each(payload.rows, function (index, row) { onComplete(index, row, that); }); }, function (err) { that.loadWorkItemsWork(idsToFetch, onComplete, that); alert(err); }); } }; As you can see, we are querying the work item store for the ID and the state of each work item on the page. We are then passing this off to an onComplete function that is using jQuery to find the elements by ID. We then alter the displayed information to show the ID, and on the task board to show the state of the requirement. If you use all the sample code and upload it into TFS, you will see a portfolio board like the one shown in the following screenshot: IDs on the portfolio board And on the task board, you will see the following screenshot: IDs and State on task board You can see that the tasks have IDs on them, which are the same as the portfolio boards, and the requirements listed on the left have IDs and their current states. Summary In this article, we covered customizing the TFS dashboard to display information that helps us find out a team's current status by pinning queries, build status, and recent changes to the source code. We then made some changes to the columns displayed in the portfolio backlog and the quick add panel. We finished off by going through what is required to create a TFS Web Access plugin. Resources for Article : Further resources on this subject: Ensuring Quality for Unit Testing with Microsoft Visual Studio 2010 [Article] Team Foundation Server 2012 [Article] The Command Line [Article]
Read more
  • 0
  • 0
  • 6919

article-image-working-common-architectures
Packt
17 Jan 2014
10 min read
Save for later

Working with common architectures

Packt
17 Jan 2014
10 min read
(For more resources related to this topic, see here.) Working with a case structure Case structure is equivalent to a conditional statement in a text-based programming language. We will create a few case structures that take different kinds of inputs, such as Boolean, numeric, string, enum, and error, to present different features of a case structure. How to do it... We will start with a Boolean case structure. The case structure in the following block diagram shows a case structure taking a Boolean input. It consists of False and True cases. The select node is also in the diagram to show that it can be used instead of a case structure when the input is Boolean. The select node will choose which input to output based on the Boolean input, similar to the case structure. The case structure in the following block diagram takes an integer as input. Keep in mind that when the input is a floating point value, it is converted into an integer. The ..-1 case will be executed when the input is less than or equal to 1. The 1, 2 case will be executed when the input is 1 or 2. The 3..5 case will be executed when the input value is between 3 and 5 inclusively. The 6.. case will be executed when the input is greater than or equal to 6. The 0, Default case will be executed when the input is 0 or does not meet the conditions of all the other cases, which is what Default means in this case. The following block diagram shows a case structure with a string input. The ''a''..''f'' case will be executed when the ASCII hex value of the input string is between a and f, including a, but excluding f. The ''f''..''j'' case will be executed when the ASCII hex value of the input string is between f and j, including f, but excluding j. If the input value does not meet the conditions of the previous states, the Default case will run. The following block diagram shows a case structure with enum input. These cases will be executed based on the input value. The Case 1 case is assigned as the default case. If the input does not meet the condition of Case 2 and Case 3, Case 1 will run by default. Enum is used for state machine, as it allows for self-documenting code. The value of an enum is also part of its type, so if we add a value in an enum type-def, the change will propagate to the rest of the block diagram. The following block diagram contains an error cluster input. It has two cases: No Error and Error. It is used extensively in a SubVI for bypassing input error, so that it doesn't get corrupted inside the SubVI. How it works... Case structure is the main way to make decisions in LabVIEW's code. It can take different types of input, such as Boolean, numeric, string, enum, and error cluster. For the Boolean case structure, sometimes it is more convenient to use the select node. It is important to note that the case structure should not be nested with too many layers and each case should be documented. Working with an event structure Event structure consists of one or more cases. Codes that are contained within a case are executed when a control event (mouse click, key stroke, and so on) or a user event (software-based event) occurs. How to do it... We will create an example that demonstrates using control event and user event for the event structure. The following example contains a numeric control (Input Num). When a number is entered, an event is triggered. For the Input Text string control, if a string is entered, an event is triggered, but no text will show up, as all the events (entering text) are discarded. When the Switch Boolean control is clicked, an event is triggered. If any event is triggered, the string indicator (Action) will update with a string that states what event has occurred. The following screenshot shows the front panel of the controls and indicator: The following screenshot shows the block diagram of the example. On the left, a Create User Event node is used to create a user event that can be generated within the code. The input user event data type is the data type used for data passing for a user event. The label of the data type in our example is Stop User, which will be used as the name of the user event. The while loop at the bottom iterates once every 500 ms, and it will generate a user event if the stop Boolean control is set to true. The event reference is registered with the Register for Events node and fed into the dynamic event terminal, which needs to be enabled by right-clicking on the frame of the event structure and then select Show Dynamic Event Terminals. In the top while loop, we see the event case that handles the event when the value of the Boolean changes for the Switch control. It is a good practice to put the control associated with the event case into the case, so that the control is easy to find and it is read by the program every time the event is triggered. When the Boolean value changes, the Action string indicator will update to show what event has occurred. The event case in the following screenshot will be executed when a key is pressed within the Input Num numeric control. The Action string indicator will update and show that the event has occurred. To create the previous event case, right-click on the event structure and select Add Event Case…. The following screenshot shows how to set up the case. Select the Input Num numeric control under Event Source and then choose which type of event to handle. The event case in the following screenshot will execute when a key is pressed within the string control, similar to the event case for the numeric control. However, notice ? behind the label of the Key Down event. This is a filter event which can discard the outcome of the event, contrary to all the previous event cases which use notify event. While our example runs as we enter values into the string control, we see that the key down event happened at the string control in the Action string indicator. The entered values do not appear in the string controls as the events are discarded. Filter events give us the ability to trigger based on an event while discarding the event as though it never happened. Notify events will trigger based on an event without interfering with the occurrence of the event. The event case in the following screenshot will execute when a timeout event occurs. In this example, the timeout event will occur in 10000 ms, if no other events occur. We can change the timeout value as we wish. If we do not want the timeout event to trigger, we can wire a -1 to the timeout input. The event case in the following screenshot will execute when a user event is generated at the bottom while loop (refer to screenshot of the complete example). Recall that the name of the user event is the label of the data type when we created the user event. The user event is generated by the bottom loop when the stop Boolean control is set to true. This way both loops can stop each other's execution. If we have to create thirty event cases manually, it can be a lot of work. The following screenshot shows an example with thirty Boolean controls. For the example, we don't have to create thirty event cases for each Boolean control. The example gets all the references of the controls on the front panel as an array and registers all the references as a dynamic event. In this event case, if any of the Boolean controls has a value change event, the case will trigger. To get more resolution, we get the reference of the control for which the event originated from and print out a text. How it works... Whenever we find ourselves wanting to use a while loop to poll user for data, we should use the event structure instead. When the event structure is waiting for an event, it does not consume any CPU resources. Working with loops Loop is a common element in programming. In LabVIEW, there is for loop, while loop, and timed loop with features that facilitate LabVIEW programming. We will go over the for loop. For the while loop, its features are very similar to the for loop, so it is omitted. How to do it... The for loop is used when a predetermined number of iteration is needed. For an undetermined number of iteration, use the while loop instead. In the following screenshot, on the left, all the features of a for loop are shown; on the right is shown the result of the example. The input of the for loop is an array with elements 3 and 6. The entry point where the array enters the for loop is a [] symbol, which means autoindexing. When the array is autoindexed, each iteration of the for loop will get an element of the array in order. Since the loop is autoindexed, the N symbol (number of iteration) at the upper-left hand corner does not need to be wired. The loop will iterate through each element of the array. In our case, the for loop will iterate two times. If multiple arrays with different lengths are wired into the for loop through autoindex, the number of times that the for loop will iterate is the size of the array with the least number of elements. The i would output the current iteration of the loop, and the stop symbol allows the program to stop the loop before completion. For enabling the conditional stop, right-click on for loop and enable the Conditional terminal. The example shows four output options. To select an option, right-click on the output terminal, select Tunnel Mode, and then select the desired option. For the last value option, the value at the very end of the array is outputted. For the Indexing option, the same number of elements as the input is outputted. For the Conditional option, we can create conditions for which elements are built into the output array. For the Concatenation option, we can concatenate to the end of a 1D array. How it works... The for loop iterates over the same code for a predetermined number of times. If the Conditional terminal is enabled, the for loop can be stopped prematurely. The for loop has many features, such as outputting the value of last iteration, indexing through an array (with and without a condition), and concatenating an array, that are useful for array processing.
Read more
  • 0
  • 0
  • 2574
article-image-bsd-socket-library
Packt
17 Jan 2014
9 min read
Save for later

BSD Socket Library

Packt
17 Jan 2014
9 min read
(For more resources related to this topic, see here.) Introduction The Berkeley Socket API (where API stands for Application Programming Interface) is a set of standard functions used for inter-process network communications. Other socket APIs also exist; however, the Berkeley socket is generally regarded as the standard. The Berkeley Socket API was originally introduced in 1983 when 4.2 BSD was released. The API has evolved with very few modifications into a part of the Portable Operating System Interface for Unix (POSIX) specification. All modern operating systems have some implementation of the Berkeley Socket Interface for connecting devices to the Internet. Even Winsock, which is MS Window's socket implementation, closely follows the Berkeley standards. BSD sockets generally rely on client/server architecture when they establish their connections. Client/server architecture is a networking approach where a device is assigned one of the two following roles: Server: A server is a device that selectively shares resources with other devices on the network Client: A client is a device that connects to a server to make use of the shared resources Great examples of the client/server architecture are web pages. When you open a web page in your favorite browser, for example https://www.packtpub.com, your browser (and therefore your computer) becomes the client and Packt Publishing's web servers become the servers. One very important concept to keep in mind is that any device can be a server, a client, or both. For example, you may be visiting the Packt Publishing website, which makes you a client, and at the same time you have file sharing enabled, which also makes your device a server. The Socket API generally uses one of the following two core protocols: Transmission Control Protocol (TCP): TCP provides a reliable, ordered, and error-checked delivery of a stream of data between two devices on the same network. TCP is generally used when you need to ensure that all packets are correctly received and are in the correct order (for example, web pages). User Datagram Protocol (UDP): UDP does not provide any of the error-checking or reliability features of TCP, but offers much less overhead. UDP is generally used when providing information to the client quickly is more important than missing packets (for example, a streaming video). Darwin, which is an open source POSIX compliant operating system, forms the core set of components upon which Mac OS X and iOS are based. This means that both OS X and iOS contain the BSD Socket Library. The last paragraph is very important to understand when you begin thinking about creating network applications for the iOS platform, because almost any code example that uses the BSD Socket Library will work on the iOS platform. The biggest difference between using the BSD Socket API on any standard Unix platform and the iOS platform is that the iOS platform does not support forking of processes. You will need to use multiple threads rather than multiple processes. The BSD Socket API can be used to build both client and server applications. There are a few networking concepts that you should understand: IP address: Any device on an Internet Protocol (IP) network, whether it is a client or server, has a unique identifier known as an IP address. The IP address serves two basic purposes: host identification and location identification. There are currently two IP address formats: IPv4: This is currently the standard for the Internet and most internal intranets. This is an example of an IPv4 address: 83.166.169.231. IPv6: This is the latest revision of the Internet Protocol (IP). It was developed to eventually replace IPv4 and to address the long-anticipated problem of running out of IPv4 addresses. This is an example of an IPv6 address: 2001:0db8:0000:0000:0000:ff00:0042:8329. An IPv6 can be shortened by replacing all the consecutive zero fields with two colons. The previous address could be rewritten as 2001:0db8::ff00:0042:8329. Ports: A port is an application or process-specific software construct serving as a communications endpoint on a device connected to an IP network, where the IP address identifies the device to connect to, and the port number identifies the application to connect to. The best way to think of network addressing is to think about how you mail a letter. For a letter to reach its destination, you must put the complete address on the envelope. For example, if you were going to send a letter to friend who lived at the following address: Your Friend 123 Main St Apt. 223 San Francisco CA, 94123 If I were to translate that into network addressing, the IP address would be equal to the street address, city, state, and zip code (123 Main St, San Francisco CA, 94123), and the apartment number would be equal to the port number (223). So the IP address gets you to the exact location, and the port number will tell you which door to knock on. A device has 65,536 available ports with the first 1024 being reserved for common protocols such as HTTP, HTTPS, SSH, and SMTP. Fully Qualified Domain Name (FQDN): As humans, we are not very good at remembering numbers; for example, if your friend tells you that he found a really excellent website for books and the address was 83.166.169.231, you probably would not remember that two minutes from now. However, if he tells you that the address was www.packtpub.com, you would probably remember it. FQDN is the name that can be used to refer to a device on an IP network. So now you may be asking yourself, how does the name get translated to the IP address? The Domain Name Server (DNS) would do that. Domain Name System Servers: A Domain Name System Server translates a fully qualified domain name to an IP address. When you use an FQDN of www.packtpub.com, your computer must get the IP address of the device from the DNS configured in your system. To find out what the primary DNS is for your machine, open a terminal window and type the following command: cat /etc/resolv.conf Byte order: As humans, when we look at a number, we put the most significant number first and the least significant number last; for example, in number 123, 1 represents 100, so it is the most significant number, while 3 is the least significant number. For computers, the byte order refers to the order in which data (not only integers) is stored into memory. Some computers store the most significant bytes first (at the lowest byte address), while others store the most significant bytes last. If a device stores the most significant bytes first, it is known as big-endian, while a device that stores the most significant bytes last is known as little-endian. The order of how data is stored in memory is of great importance when developing network applications, where you may have two devices that use different byte-ordering communication. You will need to account for this by using the Network-to-Host and Host-to-Network functions to convert between the byte order of your device and the byte order of the network. The byte order of the device is commonly referred to as the host byte order, and the byte order of the network is commonly referred to as the network byte order. Finding the byte order of your device One of the concepts that was briefly discussed in this article was how devices store information in memory (byte order). After that discussion, you may be wondering what the byte order of your device is. The byte order of a device depends on the Microprocessor architecture being used by the device. You can pretty easily go on to the Internet and search for "Mac OS X i386 byte order" and find out what the byte order is, but where is the fun in that? We are developers, so let's see if we can figure it out with code. We can determine the byte order of our devices with a few lines of C code; however, like most of the code in this article, we will put the C code within an Objective-C wrapper to make it easy to port to your projects. How to do it… Let's get started by defining an ENUM in our header file: We create an ENUM that will be used to identify the byte order of the system as shown in the following code: typedef NS_ENUM(NSUInteger, EndianType) { ENDIAN_UNKNOWN, ENDIAN_LITTLE, ENDIAN_BIG }; To determine the byte order of the device, we will use the byteOrder method as shown in the following code: -( EndianType)byteOrder { union { short sNum; char cNum[sizeof(short)]; } un; un.sNum = 0x0102; if (sizeof(short) == 2) { if(un.cNum[0] == 1 && un.cNum[1] == 2) return ENDIAN_BIG; else if (un.cNum[0] == 2 && un.cNum[1] == 1) return ENDIAN_LITTLE; else return ENDIAN_UNKNOWN; } else return ENDIAN_UNKNOWN; } How it works… In the ByteOrder header file, we defined an ENUM with three constants. The constants are as follows: ENDIAN_UNKNOWN: We are unable to determine the byte order of the device ENDIAN_LITTLE: This specifies that the most significant bytes are last (little-endian) ENDIAN_BIG: This specifies that the most significant bytes are first (big-endian) The byteOrder method determines the byte order of our device and returns an integer that can be translated using the constants defined in the header file. To determine the byte order of our device, we begin by creating a union of short int and char[]. We then store the value 0x0102 in the union. Finally, we look at the character array to determine the order in which the integer was stored in the character array. If the number one was stored first, it means that the device uses big-endian; if the number two was stored first, it means that the device uses little-endian.
Read more
  • 0
  • 0
  • 12273

article-image-article-anatomy-sprite-kit-project
Packt
16 Jan 2014
12 min read
Save for later

Anatomy of a Sprite Kit project

Packt
16 Jan 2014
12 min read
(For more resources related to this topic, see here.) A Sprite Kit project consists of things usual to any iOS project. It has the AppDelegate, Storyboard, and ViewController classes. It has the usual structure of any iOS application. However, there are differences in ViewController.view, which has the SKView class in Storyboard. You will handle everything that is related to Sprite Kit in SKView. This class will render your gameplay elements such as sprites, nodes, backgrounds, and everything else. You can't draw Sprite Kit elements on other views. It's important to understand that Sprite Kit introduces its own coordinate system. In UIkit, the origin (0,0) is located at the top-left corner, whereas Sprite Kit locates the origin at the bottom-left corner. The reason why this is important to understand is because of the fact that all elements will be positioned relative to the new coordinate system. This system originates from OpenGL, which Sprite Kit uses in implementation. Scenes An object where you place all of your other objects is the SKScene object. It represents a single collection of objects such as a level in your game. It is like a canvas where you position your Sprite Kit elements. Only one scene at a time is present on SKView. A view knows how to transition between scenes and you can have nice animated transitions. You may have one scene for menus, one for the gameplay scene, and another for the scene that features after the game ends. If you open your ViewController.m file, you will see how the SKScene object is created in the viewDidLoad method. Each SKView should have a scene, as all other objects are added to it. The scene and its object form the node tree, which is a hierarchy of all nodes present in the scene. Open the ERGMyScene.m file. Here, you can find the method where scene initialization and setup take place: - (id)initWithSize:(CGSize)size The scene holds the view hierarchy of its nodes and draws all of them. Nodes are very much like UIViews; you can add nodes as children to other nodes, and the parent node will apply its effects to all of its children, effects such as rotation or scaling, which makes working with complex nodes so much easier. Each node has a position property that is represented by CGPoint in scene coordinates, which is used to set coordinates of the node. Changing this position property also changes the node's position on the screen. After you have created a node and set its position, you need to add it to your scene node hierarchy. You can add it either to the scene or to any existing node by calling the addChild: method. You can see this in your test project with the following line: [self addChild:myLabel]; After the node has been added to a visible node or scene, it will be drawn by the scene in the next iteration of the run loop. Nodes The methods that create SKLabelNode are self-explanatory and it is used to represent text in a scene. The main building block of every scene is SKNode. Most things you can see on the screen of any given Sprite Kit game is probably a result of SKNode. Node types There are different node types that serve different purposes: SKNode: This is a parent class for different types of nodes SKSpriteNode: This is a node that draws textured sprites SKLabelNode: This is a node that displays text SKShapeNode: This is a node that renders a shape based on a Core Graphics path SKEmitterNode: This is a node that creates and renders particles SKEffectNode: This is a node that applies a Core Image filter to its children Each of them has their own initializer methods—you create one, add it to your scene, and it does the job it was assigned to do. Some node properties and methods that you might find useful are: position: This is a CGPoint representing the position of a node in its parent coordinate system. zPosition: This is a CGFloat that represents the position of a node on an imaginary Z axis. Nodes with higher zPosition will be over the nodes that have lower zPosition. If nodes have the same zPosition, the ones that were created later will appear on top of those that were created before. xScale and yScale: This is a CGFloat that allows you to change the size of any node. The default is 1.0 and setting it to any other value will change the sprite size. It is not recommended, but if you have an image of a certain resolution, scaling it will upscale the image and it will look distorted. Making nodes smaller can lead to other visual artifacts. But if you need quick and easy ways to change the size of your nodes, this property is there. name: This is the name of the node that is used to locate it in the node hierarchy. This allows you to be flexible in your scenes as you no longer need to store pointers to your nodes, and also saves you a lot of headache. childNodeWithName:(NSString *)name: This finds a child node with the specified name. If there are many nodes with the same name, the first one is returned. enumerateChildNodesWithName:usingBlock:: This allows you torun custom code on your nodes. This method is heavily used throughout any Sprite Kit game and can be used for movement, state changing, and other tasks. Actions Actions are one of the ways to add life to your game and make things interactive. Actions allow you to perform different things such as moving, rotating, or scaling nodes, playing sounds, and even running your custom code. When the scene processes its nodes, actions that are linked to these nodes are executed. To create a node, you run a class method on an action that you need, set its properties, and call the runAction: method on your node with action as a parameter. You may find some actions in the touchesBegan: method in ERGMyScene.m. In this method, you can see that a new node (of the type SKSpriteNode) is created, and then a new action is created and attached to it. This action is embedded into another action that makes it repeat forever, and then a sprite runs the action and you see a rotating sprite on the screen. To complete the preceding process, it took only five lines, and it is very intuitive. This is one of the Sprite Kit strengths—simplicity and self-documenting code. As you might have noticed, Apple names methods in a simpler way so that you can understand what it does just by reading the method. Try to adhere to the same practice and name your variables and methods so that their function can be understood immediately. Avoid naming objects a or b, use characterSprite or enemyEmitter instead. There are different action types; here we will list some that you may need in your first project: Move actions (moveTo:duration:, moveBy, followPath) are actions that move the node by a specified distance in points Rotate actions are actions that rotate your nodes by a certain angle (rotateByAngle:duration:) Actions that change node scale over time (scaleBy:duration) Actions that combine other actions (sequence: to play actions one after another, and repeatAction: to play an action a certain amount of times or forever) There are many other actions and you might look up the SKAction class reference if you want to learn more about actions. Game loop Unlike UIKit, which is based on events and waits for user input before performing any drawing or interactions, Sprite Kit evaluates all nodes, their interactions, and physics as fast as it can (capped at 60 times per second) and produces results on screen. In the following figure, you can see the way a game loop operates: First, the scene calls the update:(CFTimeInterval)currentTime method and sends it the time at which this method was invoked. The usual practice is to save the time of the last update and calculate the time that it took from the last update (delta) to the current update to move sprites by a given number of points, by multiplying the velocity of a sprite by delta, so you will get the same movement regardless of FPS. For example, if you want a sprite to move 100 pixels every second, regardless of your game performance, you multiply delta by 100. This way, if it took long to process the scene, your sprite will move slightly further for this frame; if it is processed fast, it will move just a short distance. Either way you get expected results without complex calculations. After the update is done, the scene evaluates actions, simulates physics, and renders itself on screen. This process repeats itself as soon as it's finished. This allows for smooth movement and interactions. You will write the most essential code in the update: method, since it is getting called many times per second and everything on screen happens with the code we write in this method. You will usually iterate over all objects in your scene and dispatch some job for each to do, such as character moving and bullets disappearing off screen. The update: method is not used in a template project, but it is there if you want to customize it. Let's see how we can use it to move the Hello, World! label off the screen. First, find where the label is created in the scene init method, and find this line: myLabel.text = @"Hello, World!"; Add this code right after it: myLabel.name = @"theLabel"; Find the update: method; it looks like this: - (void)update:(CFTimeInterval)currentTime Insert the following code into it: [self enumerateChildNodesWithName:@"theLabel" usingBlock:^(SKNode *node, BOOL *stop) { node.position = CGPointMake(node.position.x - 2, node.position.y); if (node.position.x < - node.frame.size.width) { node.position = CGPointMake(self.frame.size.width, node.position.y); } }]; This method first finds the child node with the name "theLabel", and as we named our label the same, it finds it and gives control to the block inside. The child that it found is a node. If it finds other nodes with the name "theLabel", it will call the same block on all of them in the order they were found. Inside the block, we change the label position by 2 pixels to the left, keeping the vertical position the same. Then, we do a check, if the position of the label from the left border of the screen is further than the length of the label, we move the label to the right-hand side of the screen. This way, we create a seamless movement that should appear to be coming out of the right-hand side as soon as the label moves off screen. But if you run the project again, you will notice that the label does not disappear. The label takes a bit longer to disappear and blinks on screen instead of moving gracefully. There are two problems with our code. The first issue is that the frame is not changing when you rotate the screen, it stays the same even if you rotate the screen. This happens because the scene size is incorrectly calculated at startup. But we will fix that using the following steps: Locate the Endless Runner project root label in the left pane with our files. It says Endless Runner, 2 targets, iOS SDK 7.0 . Select it and select the General pane on the main screen. There, find the device orientation and the checkboxes near it. Remove everything but Landscape Left and Landscape Right . We will be making our game in landscape and we don't need the Portrait mode. Next, locate your ERGViewController.m file. Find the viewDidLoad method. Copy everything after the [super viewDidLoad] call. Make a new method and add the following code: - (void) viewWillLayoutSubviews { // Configure the view. [super viewWillLayoutSubviews]; SKView * skView = (SKView *)self.view; skView.showsFPS = YES; skView.showsNodeCount = YES; // Create and configure the scene. SKScene * scene = [ERGMyScene sceneWithSize:skView.bounds.size]; scene.scaleMode = SKSceneScaleModeAspectFill; // Present the scene. [skView presentScene:scene]; } Let's see why calculations of frame size are incorrect by default. When the view has finished its load, the viewDidLoad method is getting called, but the view still doesn't have the correct frame. It is only set to the correct dimensions sometime later and it returns a portrait frame before that time. We fix this issue by setting up the scene after we get the correct frame. The second problem is the anchoring of the nodes. Unlike UIViews, which are placed on screen using their top-left corner coordinates, SKNodes are getting placed on the screen based on their anchorPoint property. The following figure explains what anchor points are. By default, the anchor point is set at (0.5, 0.5), which means that the sprite position is its center point. This comes in handy when you need to rotate the sprite, as this way it rotates around its center axis. Imagine that the square in the preceding figure is your sprite. Different anchor points mean that you use these points as the position of the sprite. The anchor point at (0, 0) means that the left-bottom corner of our sprite will be on the position of the sprite itself. If it is at (0.5, 0.5), the center of the sprite will be on the position point. Anchor points go from 0 to 1 and represent the size of the sprite. So, if you make your anchor point (0.5, 0.5), it will be exactly on sprite center. We might want to use the (0,0) anchor point for our text label. Summary In this article, we saw the different parts of the Sprite Kit project, got an idea about various objects such as scenes, nodes, and so on. Resources for Article : Further resources on this subject: Interface Designing for Games in iOS [Article] Linking OpenCV to an iOS project [Article] Creating a New iOS Social Project [Article]
Read more
  • 0
  • 0
  • 7657
Modal Close icon
Modal Close icon