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

How-To Tutorials

7019 Articles
article-image-creating-administration-interface-django
Packt
16 Oct 2009
5 min read
Save for later

Creating an Administration Interface in Django

Packt
16 Oct 2009
5 min read
Activating the Administration Interface The administration interface comes as a Django application. To activate it, we will follow a simple procedure that is similar to how we enabled the user authentication system. The admininistration application is located in the django.contrib.admin package. So the first step is adding the path of this package to the INSTALLED_APPS variable. Open settings.py, locate INSTALLED_APPS and edit it as follows: INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.admin', 'django.contrib.comments', 'django_bookmarks.bookmarks',) Next, run the following command to create the necessary tables for the administration application: $ python manage.py syncdb Now we need to make the administration interface accessible from within our site by adding URL entries for it. The administration application defines many views, so manually adding a separate entry for each view can become a tedious task. Therefore, Django provides a shortcut for this. The administration interface defines all of its URL entries in a module located at django.contrib.admin.urls, and we can include these entries in our project under a particular path by using a function called include(). Open urls.py and add the following URL entry to it: urlpatterns = ( # Admin interface (r'^admin/', include('django.contrib.admin.urls')),) This looks different from how we usually define URL entries. We are basically telling Django to retrieve all of the URL entries in the django.contrib.admin.urls module, and to include them in our application under the path ^admin/. This will make the views of the administration interface accessible from within our project. One last thing remains before we see the administration page in action. We need to tell Django what models can be managed in the administration interface. This is done by defining a class called Admin inside each model. Open bookmarks/models.py and add the highlighted section to the Link model: class Link(models.Model): url = models.URLField(unique=True) def __str__(self): return self.url class Admin: pass The Admin class defined inside the model effectively tells Django to enable the Link model in the administration interface. The keyword pass means that the class is empty. Later, we will use this class to customize the administration page, so it won't remain empty. Do the same to the Bookmark, Tag and SharedBookmark models; append an empty class called Admin to each of them. The User model is provided by Django and therefore we don't have control over it. Fortunately however, it already contains an Admin class so it's available in the administration interface by default. Next, launch the development server and direct your browser to http://127.0.0.1:8000/admin/. You will be greeted by a login page. Remember we need to create a superuser account after writing the database model. This is the account that you have to use in order to log in: Next, you will see a list of the models that are available to the administration interface. As discussed earlier, only models with a class named Admin inside them will appear on this page: If you click on a model name, you will get a list of the objects that are stored in the database under this model. You can use this page to view or edit a particular object, or to add a new one. The figure below shows the listing page for the Link model. The edit form is generated according to the fields that exist in the model. The Link form, for example, contains a single text field called Url. You can use this form to view and change the URL of a Link object. In addition, the form performs proper validation of fields before saving the object. So if you try to save a Link object with an invalid URL, you will receive an error message asking you to correct the field. The figure below shows a validation error when trying to save an invalid link: Fields are mapped to form widgets according to their type. Date fields are edited using a calendar widget for example, whereas foreign key fields are edited using a list widget, and so on. The figure below shows a calendar widget from the user edit page. Django uses it for date and time fields: As you may have noticed, the administration interface represents models by using the string returned by the __str__ method. It was indeed a good idea to replace the generic strings returned by the default __str__ method with more helpful ones. This greatly helps when working with the administration page, as well as with debugging. Experiment with the administration pages; try to create, edit and delete objects. Notice how changes made in the administration interface are immediately reflected on the live site. Also, the administration interface keeps track of the actions that you make, and lets you review the history of changes for each object. This section has covered most of what you need to know in order to use the administration interface provided by Django. This feature is actually one of the main advantages of using Django; you get a fully featured administration interface from writing only a few lines of code! Next, we will see how to tweak and customize the administration pages. And as a bonus, we will learn more about the permissions system offered by Django.
Read more
  • 0
  • 0
  • 3073

article-image-troubleshooting-lotus-notesdomino-7-applications
Packt
23 Oct 2009
19 min read
Save for later

Troubleshooting Lotus Notes/Domino 7 applications

Packt
23 Oct 2009
19 min read
Introduction The major topics that we'll cover in this article are: Testing your application (in other words, uncovering problems before your users do it for you). Asking the right questions when users do discover problems. Using logging to help troubleshoot your problems. We'll also examine two important new Notes/Domino 7 features that can be critical for troubleshooting applications: Domino Domain Monitoring (DDM) Agent Profiler   For more troubleshooting issues visit: TroubleshootingWiki.org Testing your Application Testing an application before you roll it out to your users may sound like an obvious thing to do. However, during the life cycle of a project, testing is often not allocated adequate time or money. Proper testing should include the following: A meaningful amount of developer testing and bug fixing: This allows you to catch most errors, which saves time and frustration for your user community. User representative testing: A user representative, who is knowledgeable about the application and how users use it, can often provide more robust testing than the developer. This also provides early feedback on features. Pilot testing: In this phase, the product is assumed to be complete, and a pilot group uses it in production mode. This allows for limited stress testing as well as more thorough testing of the feature set. In addition to feature testing, you should test the performance of the application. This is the most frequently skipped type of testing, because some consider it too complex and difficult. In fact, it can be difficult to test user load, but in general, it's not difficult to test data load. So, as part of any significant project, it is a good practice to programmatically create the projected number of documents that will exist within the application, one or two years after it has been fully deployed, and have a scheduled agent trigger the appropriate number of edits-per-hour during the early phases of feature testing. Although this will not give a perfect picture of performance, it will certainly help ascertain whether and why the time to create a new document is unacceptable (for example, because the @Db formulas are taking too long, or because the scheduled agent that runs every 15 minutes takes too long due to slow document searches). Asking the Right Questions Suppose that you've rolled out your application and people are using it. Then the support desk starts getting calls about a certain problem. Maybe your boss is getting an earful at meetings about sluggish performance or is hearing gripes about error messages whenever users try to click a button to perform some action. In this section, we will discuss a methodology to help you troubleshoot a problem when you don't necessarily have all the information at your disposal. We will include some specific questions that can be asked verbatim for virtually any application. The first key to success in troubleshooting an application problem is to narrow down where and when it happens. Let's take these two very different problems suggested above (slow performance and error messages), and pose questions that might help unravel them: Does the problem occur when you take a specific action? If so, what is that action? Your users might say, "It's slow whenever I open the application", or "I get an error when I click this particular button in this particular form". Does the problem occur for everyone who does this, or just for certain people? If just certain people, what do they have in common? This is a great way to get your users to help you help them. Let them be a part of the solution, not just "messengers of doom". For example, you might ask questions such as, "Is it slow only for people in your building or your floor? Is it slow only for people accessing the application remotely? Is it slow only for people who have your particular access (for example, SalesRep)?" Does this problem occur all the time, at random times, or only at certain times? It's helpful to check whether or not the time of day or the day of week/month is relevant. So typical questions might be similar to the following: "Do you get this error every time you click the button or just sometimes? If just sometimes, does it give you the error during the middle of the day, but not if you click it at 7 AM when you first arrive? Do you only get the error on Mondays or some other day of the week? Do you only see the error if the document is in a certain status or has certain data in it? If it just happens for a particular document, please send me a link to that document so that I can inspect it carefully to see if there is invalid or unexpected data." Logging Ideally, your questions have narrowed down the type of problem it could be. So at this point, the more technical troubleshooting can start. You will likely need to gather concrete information to confirm or refine what you're hearing from the users. For example, you could put a bit of debugging code into the button that they're clicking so that it gives more informative errors, or sends you an email (or creates a log document) whenever it's clicked or whenever an error occurs. Collecting the following pieces of information might be enough to diagnose the problem very quickly: Time/date User name Document UNID (if the button is pushed in a document) Error Status or any other likely field that might affect your code By looking for common denominators (such as the status of the documents in question, or access or roles of the users), you will likely be able to further narrow down the possibilities of why the problem is happening. This doesn't solve your problem of course, but it helps in advancing you a long way towards that goal. A trickier problem to troubleshoot might be one we mentioned earlier: slow performance. Typically, after you've determined that there is some kind of performance delay, it's a good idea to first collect some server logging data. Set the following Notes.ini variables in the Server Configuration document in your Domino Directory, on the Notes.ini tab: Log_Update=1Log_AgentManager=1 These variables instruct the server to write output to the log.nsf database in the Miscellaneous Events view. Note that they may already be set in your environment. If not, they're fairly unobtrusive, and shouldn't trouble your administration group. Set them for a 24-hour period during a normal business week, and then examine the results to see if anything pops out as being suspicious. For view indexing, you should look for lines like these in the Miscellaneous Events (Log_Update=1): 07/01/2006 09:29:57 AM Updating views in appsSalesPipeline.nsf07/01/2006 09:30:17 AM Finished updating views in appsSalesPipeline.nsf07/01/2006 09:30:17 AM Updating views in appsTracking.nsf07/01/2006 09:30:17 AM Finished updating views in appsTracking.nsf07/01/2006 09:30:17 AM Updating views in appsZooSchedule.nsf07/01/2006 09:30:18 AM Finished updating views in appsZooSchedule.nsf And lines like these for Agent execution (Log_AgentManager=1): 06/30/2006 09:43:49 PM AMgr: Start executing agent 'UpdateTickets' in 'appsSalesPipeline.nsf ' by Executive '1'06/30/2006 09:43:52 PM AMgr: Start executing agent 'ZooUpdate' in 'appsZooSchedule.nsf ' by Executive '2'06/30/2006 09:44:44 PM AMgr: Start executing agent 'DirSynch' in 'appsTracking.nsf ' by Executive '1' Let's examine these lines to see whether or not there is anything we can glean from them. Starting with the Log_Update=1 setting, we see that it gives us the start and stop times for every database that gets indexed. We also see that the database file paths appear alphabetically. This means that, if we search for the text string updating views and pull out all these lines covering (for instance) an hour during a busy part of the day, and copy/paste these lines into a text editor so that they're all together, then we should see complete database indexing from A to Z on your server repeating every so often. In the log.nsf database, there may be many thousands of lines that have nothing to do with your investigation, so culling the important lines is imperative for you to be able to make any sense of what's going on in your environment. You will likely see dozens or even hundreds of databases referenced. If you have hundreds of active databases on your server, then culling all these lines might be impractical, even programmatically. Instead, you might focus on the largest group of databases. You will notice that the same databases are referenced every so often. This is the Update Cycle, or view indexing cycle. It's important to get a sense of how long this cycle takes, so make sure you don't miss any references to your group of databases. Imagine that SalesPipeline.nsf and Tracking.nsf were the two databases that you wanted to focus on. You might cull the lines out of the log that have updating views and which reference these two databases, and come up with something like the following: 07/01/2006 09:29:57 AM Updating views in appsSalesPipeline.nsf07/01/2006 09:30:17 AM Finished updating views in appsSalesPipeline.nsf07/01/2006 09:30:17 AM Updating views in appsTracking.nsf07/01/2006 09:30:20 AM Finished updating views in appsTracking.nsf07/01/2006 10:15:55 AM Updating views in appsSalesPipeline.nsf07/01/2006 10:16:33 AM Finished updating views in appsSalesPipeline.nsf07/01/2006 10:16:33 AM Updating views in appsTracking.nsf07/01/2006 10:16:43 AM Finished updating views in appsTracking.nsf07/01/2006 11:22:31 AM Updating views in appsSalesPipeline.nsf07/01/2006 11:23:33 AM Finished updating views in appsSalesPipeline.nsf07/01/2006 11:23:33 AM Updating views in appsTracking.nsf07/01/2006 11:23:44 AM Finished updating views in appsTracking.nsf This gives us some very important information: the Update task (view indexing) is taking approximately an hour to cycle through the databases on the server; that's too long. The Update task is supposed to run every 15 minutes, and ideally should only run for a few minutes each time it executes. If the cycle is an hour, then that means update is running full tilt for that hour, and as soon as it stops, it realizes that it's overdue and kicks off again. It's possible that if you examine each line in the log, you'll find that certain databases are taking the bulk of the time, in which case it might be worth examining the design of those databases. But it might be that every database seems to take a long time, which might be more indicative of a general server slowdown. In any case, we haven't solved the problem; but at least we know that the problem is probably server-wide. More complex applications, and newer applications, tend to reflect server‑performance problems more readily, but that doesn't necessarily mean they carry more responsibility for the problem. In a sense, they are the "canary in the coal mine". If you suspect the problem is confined to one database (or a few), then you can increase the logging detail by setting Log_Update=2. This will give you the start time for every view in every database that the Update task indexes. If you see particular views taking a long time, then you can examine the design of those views. If no database(s) stand out, then you might want to see if the constant indexing occurs around the clock or just during business hours. If it's around the clock, then this might point to some large quantities of data that are changing in your databases. For example, you may be programmatically synchronizing many gigabytes of data throughout the day, not realizing the cost this brings in terms of indexing. If slow indexing only occurs during business hours, then perhaps the user/data load has not been planned out well for this server. As the community of users ramps up in the morning, the server starts falling behind and never catches up until evening. There are server statistics that can help you determine whether or not this is the case. (These server statistics go beyond the scope of this book, but you can begin your investigation by searching on the various Notes/Domino forums for "server AND performance AND statistics".) As may be obvious at this point, troubleshooting can be quite time-consuming. The key is to make sure that you think through each step so that it either eliminates something important, or gives you a forward path. Otherwise, you can find yourself still gathering information weeks and months later, with users and management feeling very frustrated. Before moving on from this section, let's take a quick look at agent logging. Agent Manager can run multiple agents in different databases, as determined by settings in your server document. Typically, production servers only allow two or three concurrent agents to run during business hours, and these are marked in the log as Executive '1', Executive '2', and so on. If your server is often busy with agent execution, then you can track Executive '1' and see how many different agents it runs, and for how long. If there are big gaps between when one agent starts and when the next one does (for Executive '1'), this might raise suspicion that the first agent took that whole time to execute. To verify this, turn up the logging by setting the Notes.ini variable debug_amgr=*. (This will output a fair amount of information into your log, so it's best not to leave it on for too long, but normally one day is not a problem.) Doing this will give you a very important piece of information: the number of "ticks" it took for the agent to run. One second equals 100 ticks, so if the agent takes 246,379 ticks, this equals 2,463 seconds (about 41 minutes). As a general rule, you want scheduled agents to run in seconds, not minutes; so any agent that is taking this long will require some examination. In the next section, we will talk about some other ways you can identify problematic agents. Domino Domain Monitoring (DDM) Every once in a while, a killer feature is introduced—a feature so good, so important, so helpful, that after using it, we just shake our heads and wonder how we ever managed without it for so long. Domino Domain Monitor (DDM) is just such a feature. DDM is too large to be completely covered in this one section, so we will confine our overview to what it can do in terms of troubleshooting applications. For a more thorough explanation of DDM and all its features, see the book, Upgrading to Lotus Notes and Domino (www.packtpub.com/upgrading_lotus/book). In the events4.nsf database, you will find a new group of documents you can create for tracking agent or application performance. On Domino 7 servers, a new database is created automatically with the filename ddm.nsf. This stores the DDM output you will examine. For application troubleshooting, some of the most helpful areas to track using DDM are the following: Full-text index needs to be built. If you have agents that are creating a full‑text index on the fly because the database has no full‑text index built, DDM can track that potential problem for you. Especially useful is the fact that DDM compiles the frequency per database, so (for instance) you can see if it happens once per month or once per hour. Creating full‑text indexes on the fly can result in a significant demand on server resources, so having this notification is very useful. We discuss an example of this later in this section. Agent security warnings. You can manually examine the log to try to find errors about agents not being able to execute due to insufficient access. However, DDM will do this for you, making it much easier to find (and therefore fix) such problems. Resource utilization. You can track memory, CPU, and time utilization of your agents as run by Agent Manager or by the HTTP task. This means that at any time you can open the ddm.nsf database and spot the worst offenders in these categories, over your entire server/domain. We will discuss an example of CPU usage later in this section. The following illustration shows the new set of DDM views in the events4.nsf (Monitoring configuration) database: The following screenshot displays the By Probe Server view after we've made a few document edits: Notice that there are many probes included out-of-the-box (identified by the property "author = Lotus Notes Template Development") but set to disabled. In this view, there are three that have been enabled (ones with checkmarks) and were created by one of the authors of this book. If you edit the probe document highlighted above, Default Application Code/Agents Evaluated By CPU Usage (Agent Manager), the document consists of three sections. The first section is where you choose the type of probe (in this case Application Code) and the subtype (in this case Agents Evaluated By CPU Usage). The second section allows you to choose the servers to run against, and whether you want this probe to run against agents/code executed by Agent Manager or by the HTTP task (as shown in the following screenshot). This is an important distinction. For one thing, they are different tasks, and therefore one can hit a limit while the other still has room to "breathe". But perhaps more significantly, if you choose a subtype of Agents Evaluated By Memory Usage, then the algorithms used to evaluate whether or not an agent is using too much memory are very different. Agents run by the HTTP task will be judged much more harshly than those run by the Agent Manager task. This is because with the HTTP task, it is possible to run the same agent with up to hundreds of thousands of concurrent executions. But with Agent Manager, you are effectively limited to ten concurrent instances, and none within the same database. The third section allows you to set your threshold for when DDM should report the activity: You can select up to four levels of warning: Fatal, Failure, Warning (High), and Warning (Low). Note that you do not have the ability to change the severity labels (which appear as icons in the view). Unless you change the database design of ddm.nsf, the icons displayed in the view and documents are non-configurable. Experiment with these settings until you find the approach that is most useful for your corporation. Typically, customers start by overwhelming themselves with information, and then fine-tuning the probes so that much less information is reported. In this example, only two statuses are enabled: one for six seconds, with a label of Warning (High), and one for 60 seconds, with a label of Failure. Here is a screenshot of the DDM database: Notice that there are two Application Code results, one with a status of Failure (because that agent ran for more than 60 seconds), and one with a status of Warning (High) (because that agent ran for more than six seconds but less than 60 seconds). These are the parameters set in the Probe document shown previously, which can easily be changed by editing that Probe document. If you want these labels to be different, you must enable different rows in the Probe document. If you open one of these documents, there are three sections. The top section gives header information about this event, such as the server name, the database and agent name, and so on. The second section includes the following table, with a tab for the most recent infraction and a tab for previous infractions. This allows you to see how often the problem is occurring, and with what severity. The third section provides some possible solutions, and (if applicable) automation. For example, in our example, you might want to "profile" your agent. (We will profile one of our agents in the final section of this article.) DDM can capture full-text operations against a database that is not full‑text indexed. It tracks the number of times this happens, so you can decide whether to full‑text index the database, change the agent, or neither. For a more complete list of the errors and problems that DDM can help resolve, check the Domino 7 online help or the product documentation (www.lotus.com). Agent Profiler If any of the troubleshooting tips or techniques we've discussed in this article causes you to look at an agent and think, "I wonder what makes this agent so slow", then the Agent Profiler should be the next tool to consider. Agent Profiler is another new feature introduced in Notes/Domino 7. It gives you a breakdown of many methods/properties in your LotusScript agent, telling you how often each one was executed and how long they took to execute. In Notes/Domino 7, the second (security) tab of Agent properties now includes a checkbox labeled Profile this agent. You can select this option if you want an agent to be profiled. The next time the agent runs, a profile document in the database is created and filled with the information from that execution. This document is then updated every time the agent runs. You can view these results from the Agent View by highlighting your agent and selecting Agent | View Profile Results. The following is a profile for an agent that performed slow mail searches: Although this doesn't completely measure (and certainly does not completely troubleshoot) your agents, it is an important step forward in troubleshooting code. Imagine the alternative: dozens of print statements, and then hours of collating results! Summary In closing, we hope that this article has opened your eyes to new possibilities in troubleshooting, both in terms of techniques and new Notes/Domino 7 features. Every environment has applications that users wish ran faster, but with a bit of care, you can troubleshoot your performance problems and find resolutions. After you have your servers running Notes/Domino 7, you can use DDM and Agent Profiler (both exceptionally easy to use) to help nail down poorly performing code in your applications. These tools really open a window on what had previously been a room full of mysterious behavior. Full-text indexing on the fly, code that uses too much memory, and long running agents are all quickly identified by Domino Domain Monitoring (DDM). Try it!
Read more
  • 0
  • 0
  • 3072

article-image-working-aggregators-oracle-coherence-35
Packt
27 Apr 2010
5 min read
Save for later

Working with Aggregators in Oracle Coherence 3.5

Packt
27 Apr 2010
5 min read
For example, you might want to retrieve the total amount of all orders for a particular customer. One possible solution is to retrieve all the orders for the customer using a filter and to iterate over them on the client in order to calculate the total. While this will work, you need to consider the implications: You might end up moving a lot of data across the network in order to calculate a result that is only few bytes long You will be calculating the result in a single-threaded fashion, which might introduce a performance bottleneck into your application The better approach would be to calculate partial results on each cache node for the data it manages, and to aggregate those partial results into a single answer before returning it to the client. Fortunately, we can use Coherence aggregators to achieve exactly that. By using an aggregator, we limit the amount of data that needs to be moved across the wire to the aggregator instance itself, the partial results returned by each Coherence node the aggregator is evaluated on, and the final result. This reduces the network traffic significantly and ensures that we use the network as efficiently as possible. It also allows us to perform the aggregation in parallel, using full processing power of the Coherence cluster. At the very basic, an aggregator is an instance of a class that implements the com.tangosol.util.InvocableMap.EntryAggregator interface: interface EntryAggregator extends Serializable {Object aggregate(Set set);} However, you will rarely have the need to implement this interface directly. Instead, you should extend the com.tangosol.util.aggregator.AbstractAggregator class that also implements the com.tangosol.util.InvocableMap.ParallelAwareAggregator interface, which is required to ensure that the aggregation is performed in parallel across the cluster. The AbstractAggregator class has a constructor that accepts a value extractor to use and defines the three abstract methods you need to override: public abstract class AbstractAggregatorimplements InvocableMap.ParallelAwareAggregator {public AbstractAggregator(ValueExtractor valueExtractor) {...}protected abstract void init(boolean isFinal);protected abstract void process(Object value, boolean isFinal);protected abstract Object finalizeResult(boolean isFinal);} The init method is used to initialize the result of aggregation, the process method is used to process a single aggregation value and include it in the result, and the finalizeResult method is used to create the final result of the aggregation. Because aggregators can be executed in parallel, the init and finalizeResult methods accept a flag specifying whether the result to initialize or finalize is the final result that should be returned by the aggregator or a partial result, returned by one of the parallel aggregators. The process method also accepts an isFinal flag, but in its case the semantics are somewhat different—if the isFinal flag is true, that means that the object to process is the result of a single parallel aggregator execution that needs to be incorporated into the final result. Otherwise, it is the value extracted from a target object using the value extractor that was specified as a constructor argument. This will all be much clearer when we look at an example. Let's write a simple aggregator that returns an average value of a numeric attribute: public class AverageAggregatorextends AbstractAggregator {private transient double sum;private transient int count;public AverageAggregator() {// deserialization constructor}public AverageAggregator(ValueExtractor valueExtractor) {super(valueExtractor);}public AverageAggregator(String propertyName) {super(propertyName);}protected void init(boolean isFinal) {sum = 0;count = 0;}protected void process(Object value, boolean isFinal) {if (value != null) {if (isFinal) {PartialResult pr = (PartialResult) o;sum += pr.getSum();count += pr.getCount();}else {sum += ((Number) o).doubleValue();count++;}}}protected Object finalizeResult(boolean isFinal) {if (isFinal) {return count == 0 ? null : sum / count;}else {return new PartialResult(sum, count);}}static class PartialResult implements Serializable {private double sum;private int count;PartialResult(double sum, int count) {this.sum = sum;this.count = count;}public double getSum() {return sum;}public int getCount() {return count;}}} As you can see, the init method simply sets both the sum and the count fields to zero, completely ignoring the value of the isFinal flag. This is OK, as we want those values to start from zero whether we are initializing our main aggregator or one of the parallel aggregators. The finalizeResult method, on the other hand, depends on the isFinal flag to decide which value to return. If it is true, it divides the sum by the count in order to calculate the average and returns it. The only exception is if the count is zero, in which case the result is undefined and the null value is returned. However, if the isFinal flag is false, the finalizeResult simply returns an instance of a PartialResult inner class, which is nothing more than a holder for the partial sum and related count on a single node. Finally, the process method also uses the isFinal flag to determine its correct behavior. If it's true, that means that the value to be processed is a PartialResult instance, so it reads partial sum and count from it and adds them to the main aggregator's sum and count fields. Otherwise, it simply adds the value to the sum field and increments the count field by one. We have implemented AverageAggregator in order to demonstrate with a simple example how the isFinal flag should be used to control the aggregation, as well as to show that the partial and the final result do not have to be of the same type. However, this particular aggregator is pretty much a throw-away piece of code, as we'll see in the next section.
Read more
  • 0
  • 0
  • 3070

article-image-performing-hand-written-digit-recognition-golearn
Alex Browne
31 Mar 2015
9 min read
Save for later

Performing hand-written digit recognition with GoLearn

Alex Browne
31 Mar 2015
9 min read
In this step-by-step post, you'll learn how to do basic recognition of hand-written digits using GoLearn, a machine learning library for Go. I'll assume you are already comfortable with Go and have a basic understanding of machine learning. To learn Go, I recommend the interactive tutorial. And to learn about machine learning, I recommend Andrew Ng's Machine Learning course on Coursera. All of the code for this tutorial is available on github. Installation & Set Up  To follow along with this post, you will need to install: Go version 1.2 or later The GoLearn package Also, make sure that you follow these intructions for setting up your go work environment. In particular, you will need to have the GOPATH environment variable pointing to a directory where all of your Go code will reside. Project Structure Now is a good time to setup the directory where your code for this project will reside. Somewhere in your $GOPATH/src, create a new directory and call it whatever you want. I recommend $GOPATH/src/github.com/your-github-username/golearn-digit-recognition. Our basic project structure is going to look like this: golearn-digit-recognition/ data/ mnist_train.csv mnist_test.csv main.go The data directory is where we'll put our training and test data, and our program is going to consist of a single file: main.go. Getting the Training Data As I mentioned, in this post we're going to be using GoLearn to recognize hand-written digits. The training data we'll use comes from the popular MNIST handwritten digit database. I've already split the data into training and test sets and formatted it in the way GoLearn expects. You can simply download the CSV files and put them in your data directory:  Training Data Test Data The data consists of a series of 28x28 pixel grayscale images and labels for the corresponding digit (0-9). 28x28 = 784 so there are 784 features. In the CSV files, the pixels are labeled pixel0-pixel783. Each pixel can take on a value between 0 and 255, where 0 is white and 255 is black. There are 5,000 rows in the training data, and 500 in the test data. Writing the Code Without further ado, let's write a simple program to detect hand-written digits. Open up the main.go file in your favorite text editor and add the following lines: package main import ( "fmt" "github.com/sjwhitworth/golearn/base" ) func main() { // Load and parse the data from csv files fmt.Println("Loading data...") trainData, err := base.ParseCSVToInstances("data/mnist_train.csv", true) if err != nil { panic(err) } testData, err := base.ParseCSVToInstances("data/mnist_test.csv", true) if err != nil { panic(err) } } The ParseCSVToInstances function reads the CSV file and converts it into "Instances," which is simply a data structure that GoLearn can understand and manipulate. You should run the program with go run main.go to make sure everything works so far. Next, we're going to create a linear Support Vector Classifier, which is a type of Support Vector Machine where the output is the probability that the input belongs to some class. In our case, there are 10 possible classes representing the digits 0 through 9, so our SVC will consist of 10 SVMs, each of which outputs the probability that the input belongs to a certain class. The SVC will then simply output the class with the highest probability.  Modify main.go by importing the linear_models package from golearn: import (     // ...     "github.com/sjwhitworth/golearn/linear_models" ) Then add the following lines: func main() {           // ...        // Create a new linear SVC with some good default values      classifier, err := linear_models.NewLinearSVC("l1", "l2", true, 1.0, 1e-4)      if err != nil {           panic(err)      }        // Don't output information on each iteration      base.Silent()        // Train the linear SVC      fmt.Println("Training...")      classifier.Fit(trainData) }   You can read more about the different parameters for the SVC here. I found that these parameters give pretty good results. After we've created the classifier, training it is as simple as calling classifier.Fit(). Now might be a good time to run go run main.go again to make sure everything compiles and works as expected. If you want to see some details about what's going on with the classifier, comment out or remove the base.Silent() line. Finally, we can test the accuracy of our SVC by making predictions on the test data and then comparing our predictions to the expected output. GoLearn makes it really easy to do this. Just modify main.go as follows: package main   import (      // ...      "github.com/sjwhitworth/golearn/evaluation"     // ... )   func main() {           // ...        // Make predictions for the test data      fmt.Println("Predicting...")      predictions, err := classifier.Predict(testData)      if err != nil {           panic(err)      }        // Get a confusion matrix and print out some accuracy stats for our predictions      confusionMat, err := evaluation.GetConfusionMatrix(testData, predictions)      if err != nil {           panic(fmt.Sprintf("Unable to get confusion matrix: %s", err.Error()))      }      fmt.Println(evaluation.GetSummary(confusionMat)) }     After making the predictions for our test data, we use the evaluation package to quickly get some stats about the accuracy of our classifier. You should run the program again with go run main.go. If everything works correctly, you should see output that looks something like this:  Loading data...Training...Predicting...Reference Class     True Positives     False Positives     True Negatives     Precision     Recall     F1 Score---------------     --------------     ---------------     --------------     ---------     ------     --------6          42          4          447          0.9130          0.8571     0.88425          31          15          444          0.6739          0.7561     0.71268          37          7          445          0.8409          0.7708     0.80437          47          5          440          0.9038          0.8545     0.87852          51          6          434          0.8947          0.8500     0.87183          35          9          448          0.7955          0.8140     0.80461          50          5          443          0.9091          0.9615     0.93464          48          4          441          0.9231          0.8727     0.89720          41          3          455          0.9318          0.9762     0.95359          49          11          434          0.8167          0.8909     0.8522Overall accuracy: 0.8620 That's about an 86% accuracy. Not too bad! And all it took was a few lines of code! Summary If you want to do even better, try playing around with the parameters for the SVC or use a different classifier. GoLearn has support for linear and logistic regression, K nearest neighbor, neural networks, and more! About the author Alex Browne is a recent college grad living in Raleigh NC with 4 years of professional software experience. He does software contract work to make ends meet, and spends most of his free time learning new things and working on various side projects. He is passionate about open source technology and has plans to start his own company.
Read more
  • 0
  • 0
  • 3064

article-image-introduction-rhomobile
Packt
21 Jul 2011
6 min read
Save for later

An introduction to Rhomobile

Packt
21 Jul 2011
6 min read
The Rhomobile family Rhomobile Inc. is a computer software company that provides leading products for building the new generation of mobile applications. It offers an open-source Ruby-based mobile development framework for business mobility solutions through its four major products Rhodes, RhoSync, Rhohub, and RhoGallery. Rhodes Rhodes is an open source framework by Rhomobile. It develops native applications for almost all smart phones. The applications built through Rhodes are pure native applications and use device capabilities such as GPS, PIM contacts and calendar, camera, native mapping, push, barcode, signature capture, and Bluetooth. Rhodes accelerates the development of mobile applications without compromising on its portability. This framework is similar to the popular Rails framework. It is based on Model view Controller and has inbuilt Object Relational Manager (ORM) called Rhom that is similar to active Record in Rails. Most user interface customization can be done in HTML templates (ERB, eruby files). A single set of source written with Rhodes can be compiled to run across all of the supported smart phones. This means that we will have the same code base for all your devices. RhoSync RhoSync is a standalone mobile sync server that keeps enterprise application data up to date and available on users' smart phones. Enterprise apps require local synchronized data to be used most of the time. The information is stored locally on a users' device and is available to them even in offline mode. It is very easy to write a source adapter as RhoSync generates most of the code while creating the source adapter. The source adapter can also be used to Create, Read, Update, and Delete (CRUD) operations on a model. Rhosync uses Redis, which is a NoSql Key Value store for data caching. This makes Rhosync more scalable. RhoSync performs its push-based sync using the native smartphone push SDKs. It uses new advanced BlackBerry Enterprise Server and iPhone 3.0 SDKs for Push. It uses BES Push and iPhone Push for synchronization, allowing real-time updates of backend application information. RhoHub RhoHub is a hosted development environment for Rhodes and Rhosync. The RhoSync application will be deployed on the famous Ruby cloud Heroku with the interface of RhoHub. RhoHub enables git-powered source control and collaboration with your team. It allows us to directly build an application for different smart phones without installing SDKs. It makes the process of the build very smooth since we don't have to install any development toolkits. It is only a one click process that automatically creates a build for most of the smart phones. Rhohub provides us with the following functionalities: Creating a build for a Rhodes application Deploying the Rhosync application to the cloud Providing version control with git Managing collaborators RhoGallery RhoGallery provides a hosted mobile app management solution. It allows administrators to manage the set of apps exposed to their users. It also makes it easy for them to get mobile apps onto their devices. It enables users to launch all of their important enterprise apps from a single place. RhoGallery consists of a management console for "app galleries" on RhoHub, as well as a RhoGallery App that users load onto their devices. Even for an individual developer with one or a few apps, RhoGallery makes it easy to expose those apps to their users. RhoGallery handles inviting the users and determining the appropriate downloads to provide to them. RhoGallery provides the following functionalities: Administrator management of exposed apps to end users Central user launching of exposed apps Automatic provisioning of appropriate apps for end users Why Rhomobile is cutting edge The following features give a cutting edge to Rhomobile in mobile application development: Model View Controller: Most of the other frameworks available in the market are based on HTML and JavaScript. However, as Rhodes is a Ruby-based framework and its structure is similar to the popular framework Rails, it also supports Model View Controller, so code written with Rhodes is more structured and easy to understand. Cross Platform Support for All Devices: Rhodes supports the following devices: Android, Windows Mobile, BlackBerry, and iphone. The best thing is you have a single code base from which you can build applications for different smart phones. It does not work in a traditional way in that we have to write separate code for different types of phones. Offline Capabilities using Rhosync: Rhomobile supports local synchronization of data. As we can synchronize the data using Rhosync it provides offline Capabilities. It can work even if you are offline. Object Relational Manager: Rhodes provides an inbuilt Object Relational Manager called Rhom. It is similar to Active Record in Rails but with basic functionality only. It helps us to write queries without thinking about which database is being used by phone. Rapid Development: One of the most interesting features of Rhodes is that it imposes some fairly serious constraints on how you structure the applications that help us for rapid development. Rhomobile products are properly structured and well organized, which enforce us to do rapid development. Rhodes is very comfortable, familiar, and massively productive. Scalable Sync Server: The Sync Server uses a NoSql Database which makes it scalable. Specifically, it is the only sync server that has a built-in "no SQL" Redis key value store, making it more scalable than other sync servers which offer internal relational database servers for caching. RhoSync also performs its push-based sync using the native smart phone push SDKs, which no other sync server does. Liberal use of code generation: Rhodes/RhoSync can write a lot of code for you. For example, when you need a class to represent a table in your database, you don't have to write most of the methods. Rhodes even offers an application generator that creates an initial app based on the structure of your models or business objects in your app. It's very similar to the scaffolding offered by most modern web frameworks with basic list/create/read/update/delete objects functionality. For each basic CRUD action, views in HTML are also offered. You'll find that you're writing only a fraction of code compared to other frameworks. Metadata: Every enterprise application that is used to run a company's core business has a different schema for its business objects. For example, every application has a varying and customized structure that changes with time. It is not possible to install the client application again and again for a small change. The Metadata framework provides a way to handle the view from the Rhosync server. It also provides validation and a custom template. Hosted Development and Build: Rhomobile also provides a hosted management and Build through Rhohub. We can deploy a Rhosync app and build our Rhodes code for different phones with it.
Read more
  • 0
  • 0
  • 3063

article-image-creating-basic-vaadin-project
Packt
13 Dec 2011
10 min read
Save for later

Creating a Basic Vaadin Project

Packt
13 Dec 2011
10 min read
  (For more resources on this topic, see here.)   Understanding Vaadin In order to understand Vaadin, we should first understand what is its goal regarding the development of web applications. Vaadin's philosophy Classical HTML over HTTP application frameworks are coupled to the inherent request/response nature of the HTTP protocol. This simple process translates as follows: The client makes a request to access an URL. The code located on the server parses request parameters (optional). The server writes the response stream accordingly. The response is sent to the client. All major frameworks (and most minor ones, by the way) do not question this model: Struts, Spring MVC, Ruby on Rails, and others, completely adhere to this approach and are built upon this request/response way of looking at things. It is no mystery that HTML/HTTP application developers tend to comprehend applications through a page-flow filter. On the contrary, traditional client-server application developers think in components and data binding because it is the most natural way for them to design applications (for example, a select-box of countries or a name text field). A few recent web frameworks, such as JSF, tried to cross the bridge between components and page-flow, with limited success. The developer handles components, but they are displayed on a page, not a window, and he/she still has to manage the flow from one page to another. The Play Framework (http://www.playframework.org/) takes a radical stance on the page-flow subject, stating that the Servlet API is a useless abstraction on the request/response model and sticks even more to it. Vaadin's philosophy is two-fold: It lets developers design applications through components and data bindings It isolates developers as much as possible from the request/response model in order to think in screens and not in windows This philosophy lets developers design their applications the way it was before the web revolution. In fact, fat client developers can learn Vaadin in a few hours and start creating applications in no time. The downside is that developers, who learned their craft with the thin client and have no prior experience of fat client development, will have a hard time understanding Vaadin as they are inclined to think in page-flow. However, they will be more productive in the long run. Vaadin's architecture In order to achieve its goal, Vaadin uses an original architecture. The first fact of interest is that it is comprised of both a server and a client side. The client side manages thin rendering and user interactions in the browser The server side handles events coming from the client and sends changes made to the user interface to the client Communication between both tiers is done over the HTTP protocol. We will have a look at each of these tiers.   Client server communication Messages in Vaadin use three layers: HTTP, JSON, and UIDL. The former two are completely un-related to the Vaadin framework and are supported by independent third parties; UIDL is internal. HTTP protocol Using the HTTP protocol with Vaadin has the following two main advantages: There is no need to install anything on the client, as browsers handle HTTP (and HTTPS for that matter) natively. Firewalls that let pass the HTTP traffic (a likely occurrence) will let Vaadin applications function normally. JSON message format Vaadin messages between the client and the server use JavaScript Objects Notation (JSON). JSON is an alternative to XML that has the following several differences: First of all, the JSON syntax is lighter than the XML syntax. XML has both a start and an end tag, whereas JSON has a tag coupled with starting brace and ending brace. For example, the following two code snippets convey the same information, but the first requires 78 characters and the second only 63. For a more in depth comparison of JSON and XML, refer to the following URL: http://json.org/xml.html <person> <firstName>John</firstName> <lastName>Doe</lastName> </person> {"person" { {"firstName": "John"}, {"lastName": "Doe"} } The difference varies from message to message, but on an average, it is about 40%. It is a real asset only for big messages, and if you add server GZIP compression, size difference starts to disappear. The reduced size is no disadvantage though. Finally, XML designers go to great length to differentiate between child tags and attributes, the former being more readable to humans and the latter to machines. JSON messages design is much simpler as JSON has no attributes. UIDL "schema" The last stack that is added to JSON and HTTP is the User Interface Definition Language (UIDL). UIDL describes complex user interfaces with JSON syntax. The good news about these technologies is that Vaadin developers won't be exposed to them. The client part The client tier is a very important tier in web applications as it is the one with which the end user directly interacts. In this endeavor, Vaadin uses the excellent Google Web Toolkit (GWT) framework. In the GWT development, there are the following mandatory steps: The code is developed in Java. Then, the GWT compiler transforms the Java code in JavaScript. Finally, the generated JavaScript is bundled with the default HTML and CSS files, which can be modified as a web application. Although novel and unique, this approach provides interesting key features that catch the interest of end users, developers, and system administrators alike: Disconnected capability, in conjunction with HTML 5 client-side data stores Displaying applications on small form factors, such as those of handheld devices Development only with the Java language Excellent scalability, as most of the code is executed on the client side, thus freeing the server side from additional computation On the other hand, there is no such thing as a free lunch! There are definitely disadvantages in using GWT, such as the following: The whole coding/compilation/deployment process adds a degree of complexity to the standard Java web application development. Although a Google GWT plugin is available for Eclipse and NetBeans, IDEs do not provide standard GWT development support. Using GWT development mode directly or through one such plugin is really necessary, because without it, developing is much slower and debugging almost impossible. For more information about GWT dev mode, please refer to the following URL: http://code.google.com/intl/en/webtoolkit/doc/latest/DevGuideCompilingAndDebugging.html There is a consensus in the community that GWT has a higher learning curve than most classic web application frameworks; although the same can be said for others, such as JSF. If the custom JavaScript is necessary, then you have to bind it in Java with the help of a stack named JavaScript Native Interface (JSNI), which is both counter-intuitive and complex. With pure GWT, developers have to write the server-side code themselves (if there is any). Finally, if ever everything is done on the client side, it poses a great security risk. Even with obfuscated code, the business logic is still completely open for inspection from hackers. Vaadin uses GWT features extensively and tries to downplay its disadvantages as much as possible. This is all possible because of the Vaadin server part. The server part Vaadin's server-side code plays a crucial role in the framework. The biggest difference in Vaadin compared to GWT is that developers do not code the client side, but instead code the server side that generates the former. In particular, in GWT applications, the browser loads static resources (the HTML and associated JavaScript), whereas in Vaadin, the browser accesses the servlet that serves those same resources from a JAR (or the WEB-INF folder). The good thing is that it completely shields the developer from the client-code, so he/she cannot make unwanted changes. It may be also seen as a disadvantage, as it makes the developer unable to change the generated JavaScript before deployment. It is possible to add custom JavaScript, although it is rarely necessary. In Vaadin, you code only the server part! There are two important tradeoffs that Vaadin makes in order achieve this: As opposed to GWT, the user interface related code runs on the server, meaning Vaadin applications are not as scalable as pure GWT ones. This should not be a problem in most applications, but if you need to, you should probably leave Vaadin for some less intensive part of the application; stick to GWT or change an entirely new technology. While Vaadin applications are not as scalable as applications architecture around a pure JavaScript frontend and a SOA backend, a study found that a single Amazon EC2 instance could handle more than 10,000 concurrent users per minute, which is much more than your average application. The complete results can be found at the following URL: http://vaadin.com/blog/-/blogs/vaadin-scalabilitystudy-quicktickets Second, each user interaction creates an event from the browser to the server. This can lead to changes in the user interface's model in memory and in turn, propagate modifications to the JavaScript UI on the client. The consequence is that Vaadin applications simply cannot run while being disconnected from the server! If your requirements include the offline mode, then forget Vaadin. Terminal and adapter As in any low-coupled architecture, not all Vaadin framework server classes converse with the client side. In fact, this is the responsibility of one simple interface: com.vaadin.terminal.Terminal. In turn, this interface is used by a part of the framework aptly named as the Terminal Adapter, for it is designed around the Gang of Four Adapter (http://www.vincehuston.org/dp/adapter.html) pattern. This design allows for the client and server code to be completely independent of each other, so that one can be changed without changing the other. Another benefit of the Terminal Adapter is that you could have, for example, other implementations for things such as Swing applications. Yet, the only terminal implementation provided by the current Vaadin implementation is the web browser, namely com.vaadin.terminal.gwt.server.WebBrowser. However, this does not mean that it will always be the case in the future. If you are interested, then browse the Vaadin add-ons directory regularly to check for other implementations, or as an alternative, create your own! Client server synchronization The biggest challenge when representing the same model on two heterogeneous tiers is synchronization between each tier. An update on one tier should be reflected on the other or at least fail gracefully if this synchronization is not possible (an unlikely occurrence considering the modern day infrastructure). Vaadin's answer to this problem is a synchronization key generated by the server and passed on to the client on each request. The next request should send it back to the server or else the latter will restart the current session's application. This may be the cause of the infamous and sometimes frustrating "Out of Sync" error, so keep that in mind.  
Read more
  • 0
  • 0
  • 3062
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-getting-started-openstreetmap
Packt
21 Sep 2010
6 min read
Save for later

Getting Started with OpenStreetMap

Packt
21 Sep 2010
6 min read
(For more resources on OpenStreetMap, see here.) Not all the tools and features on the site are obvious from the front page, so we'll go on a tour of the site, and cover some other tools hosted by the project. By the end of the article, you should have a good idea about where to find answers to the questions you have about OpenStreetMap. A quick tour of the front page The project's main "shop front" is www.openstreetmap.org. It's the first impression most people get of what OpenStreetMap does, and is designed to be easy to use, rather than show as much information as possible. In the following diagram, you can see the layout of the front page. We'll be referring to many of the features on the front page, so let's have a look at what's there: Most of the page is taken up by the map viewer, which is nicknamed the slippy map by mappers. This has its own controls, which we'll cover later in the article. Along the top of the map are the navigation tabs, showing most of the data management tools on openstreetmap.org. To the right of these are the user account links. Down the left-hand side of the page is the sidebar, containing links to the wiki, news blog, merchandise page, and map key. The wiki is covered later in this article. The news blog is www.opengeodata.org, and it's an aggregation of many OSM-related blogs. The Shop page is a page on the wiki listing various pieces of OpenStreetMap-related merchandise from several sources. Most merchandise generates income for the OpenStreetMap Foundation or a local group. Clicking on the map key will show the key on the left-hand side of the map. As you'd expect, the key shows what the symbols and shading on the map mean. The key is dynamic, and will change with zoom level and which base layer you're looking at. Not all base layers are supported by the dynamic map key at present. Below this is the search box. The site search uses two separate engines: Nominatim: This is an OpenStreetMap search engine or geocoder. This uses the OpenStreetMap database to find features by name, including settlements, streets, and points of interest. Nominatim is usually fast and accurate, but can only find places that have been mapped in OpenStreetMap. Geonames: This is an external location service that has greater coverage than OpenStreetMap at present, but can sometimes be inaccurate. Geonames contains settlement names and postcodes, but few other features. Clicking on a result from either search engine will center the map on that result and mark it with an arrow. Creating your account To register, go to http://www.openstreetmap.org/, and choose sign up in the top right-hand corner. This will take you to the following registration form: At present, you only really need an account on openstreetmap.org if you're planning to contribute mapping data to the project. Outside the main site and API, only the forums and issue tracker use the same username and password as openstreetmap.org. You don't need to register to download data, export maps, or subscribe to the mailing lists. Conversely, even if you're not planning to do any mapping, there are still good reasons to register at the site, such as the ability to contact and be contacted by other mappers. OpenStreetMap doesn't allow truly anonymous editing of data. T he OSM community decided to disallow this in 2007, so that any contributors could be contacted if necessary. If you're worried about privacy, you can register using a pseudonym, and this will be the only identifying information used for your account. Registering with openstreetmap.org requires a valid e-mail address, but this is never disclosed to any other user under any circumstance, unless you choose to do so. It is possible to change your display name after registration, and this changes it for all current OpenStreetMap data. However, it won't change in any archived data, such as old planet files. Once you've completed the registration form, you'll receive an e-mail asking you to confirm the registration. Your account won't be active until you click on the link in this e-mail. Once you've activated your account, you can change your settings, as follows: You can add a short description of yourself if you like, and add a photo of yourself or some other avatar. You can also set your home location by clicking on it in the small slippy map on your settings page. This allows other mappers nearby to see who else is contributing in their area, and allows you to see them. You don't have to use your house or office as your home location; any place that gives a good idea of where you'll be mapping is enough. Adding a location may lead to you being invited to OpenStreetMap-related events in your area, such as mapping parties or social events. If you do add a location, you get a home link in your user navigation on the home page that will take the map view back to that place. You'll also see a map on your user page showing other nearby mappers limited to the nearest 10 users within 50km. If you know other mappers personally, you can indicate this by adding them as your friend on openstreetmap.org. This is just a convenience to you, and your friends aren't publicly shown on your user page, although anyone you add as a friend will receive an e-mail telling them you've done it. Once you've completed the account settings, you can view your user page (shown in the following screenshot). You can do this at any time by clicking on your display name in the top right-hand corner. This shows the information about yourself that you've just entered, links to your diary and to add a new diary entry, a list of your edits to OpenStreetMap, your GPS traces, and to your settings. These will be useful once you've done some mapping, and when you need to refer to others' activities on the site. Every user on openstreetmap.org has a diary that they can use to keep the community informed of what they've been up to. Each diary entry can have a location attached, so you can see where people have been mapping. There's an RSS feed for each diary, and a combined feed for all diary entries. You can find any mapper's diary using the link on their user page, and you can comment on other mappers' diary entries, and they'll get an e-mail notification when you do.
Read more
  • 0
  • 0
  • 3062

article-image-hooking-native-events
Packt
04 Jan 2013
9 min read
Save for later

Hooking into native events

Packt
04 Jan 2013
9 min read
(For more resources related to this topic, see here.) Pausing your application Although we want our users to spend their time solely on our applications, they will inevitably leave our application to open another one or do something else entirely. We need to be able to detect when a user has left our application but not closed it down entirely. How to do it... We can use the PhoneGap API to fire off a particular event when our application is put into the background on the device: Create the initial HTML layout for the application, and include the reference to the Cordova JavaScript file in the head tag of the document. <!DOCTYPE HTML> <html> <head> <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width;" /> <meta http-equiv="Content-type" content="text/html;> <title>Pausing an application</title> <script type="text/javascript" src="cordova-2.0.0.js"></script> </head> <body> </body> </html> Before the closing head tag, create a new script tag block and add the event listener to check when the device is ready and the PhoneGap code is ready to run. <script type="text/javascript"> document.addEventListener("deviceready", onDeviceReady, false); </script> Create the onDeviceReady function, which will run when the event listener is fired. Inside this, we'll create a new event listener that will check for a pause event, and once received will fire the onPause method. function onDeviceReady() { document.addEventListener("pause", onPause, false); } Let's create the onPause method. In this example application, we'll ask the device to notify the user that the application has moved into the background by playing an audio beep. The numeric parameter specifies how many times we want the audio notification to be played — in this case, just once. function onPause() { navigator.notification.beep(1); } Developing for iOS? There is no native beep API for iOS. The PhoneGap API will play an audio file using the media API, but the developer must provide the file, named beep.wav and under 30 seconds in length, in the /www directory of the application project files. iOS will also ignore the beep count argument and will play the audio once. If developing for Windows 7 mobile, the WP7 Cordova library contains a generic beep audio file that will be used. When we run the application on the device, if you press the home button or navigate to another application, the device will play the notification audio. How it works... To correctly determine the flow of our lifecycle events, we first set up the deviceready event listener to ensure that the native code was properly loaded. At this point, we were then able to set the new event listener for the pause event. As soon as the user navigated away from our application, the native code would set it into the background processes on the device and fire the pause event, at which point our listener would run the onPause method. To find out more about the pause event, please refer to the official documentation, available here: http://docs.phonegap.com/en/2.0.0/cordova_events_events.md.html#pause. There's more... In this recipe we applied the pause event in an incredibly simple manner. There is a possibility your application will want to do something specific other than sending an audio notification when the user pauses your application. For example, you may want to save and persist any data currently in the view or in memory, such as any draft work (if dealing with form inputs) or saving responses from a remote API call. We'll build an example that will persist data in the next recipe, as we'll be able to quantify its success when we resume the use of the application and bring it back into the foreground. Resuming your application Multi-tasking capabilities that are now available on mobile devices specify that the user has the ability to switch from one application to another at any time. We need to handle this possibility and ensure that we can save and restore any processes and data when the user returns to our application. How to do it... We can use the PhoneGap API to detect when our application is brought back into the foreground on the device. The following steps will help us to do so: Create the initial layout for the HTML and include the JavaScript references to the Cordova and the xui.js files. We will also be setting the deviceready listener once the DOM has fully loaded, so let's apply an onload attribute to the body tag. <!DOCTYPE HTML> <html> <head> <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width;" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <title>Resuming an application</title> <script type="text/javascript" src="cordova-2.0.0.js"></script> <script type="text/javascript" src="xui.js"></script> </head> <body onload="onLoad()"> </body> </html> Create a new script tag block before the closing head tag and add the deviceready event listener within the onLoad method. We'll also set two global variables, savedTime, and localStorage, the latter of which will reference the localStorage API on the device: <script type="text/javascript"> var savedTime; var localStorage = window.localStorage; function onLoad() { document.addEventListener("deviceready", onDeviceReady, false); } </script> Create the onDeviceReady function, within which we'll set the two event listeners to check for the pause and resume events, as follows: function onDeviceReady() { document.addEventListener("pause", onPause, false); document.addEventListener("resume", onResume, false); } We can now add the first of the new callback functions for the added listeners. onPause will run when a pause event has been detected. In this method, we'll create a new date variable holding the current time, and store it into the global savedTime variable we created earlier. If the user has entered something in to the text input field, we'll also take the value and set it into the localStorage API, before clearing out the input field. function onPause() { savedTime = new Date(); var strInput = x$('#userInput').attr('value'); if(strInput) { localStorage.setItem('saved_input', strInput); x$('#userInput').attr('value', ''); } } Define the onResume method, which will run when a resume event has been detected. In this function, we'll save a new date variable and we'll use it in conjunction with the savedTime variable created in the onPause method to generate the time difference between the two dates. We'll then create a string message to display the time details to the user. We'll then check the localStorage for the existence of an item stored using the key saved_input. If this exists, we'll extend the message string and append the saved user input value before setting the message into the DOM to display. function onResume() { var currentTime = new Date(); var dateDiff = currentTime.getTime() - savedTime.getTime(); var objDiff = new Object(); objDiff.days = Math.floor(dateDiff/1000/60/60/24); dateDiff -= objDiff.days*1000*60*60*24; objDiff.hours = Math.floor(dateDiff/1000/60/60); dateDiff -= objDiff.hours*1000*60*60; objDiff.minutes = Math.floor(dateDiff/1000/60); dateDiff -= objDiff.minutes*1000*60; objDiff.seconds = Math.floor(dateDiff/1000); var strMessage = '<h2>You are back!</h2>' strMessage += '<p>You left me in the background for ' strMessage += '<b>' + objDiff.days + '</b> days, ' strMessage += '<b>' + objDiff.hours + '</b> hours, ' strMessage += '<b>' + objDiff.minutes + '</b> minutes, ' strMessage += '<b>' + objDiff.seconds + '</b> seconds.</p>'; if(localStorage.getItem('saved_input')) { strMessage = strMessage + '<p>You had typed the following before you left:<br /><br />' strMessage += '"<b>' + localStorage.getItem('saved_input') + '</b>"</p>'; } x$('#message').html(strMessage); } Finally, let's add the DOM elements to the application. Create a new div element with the id attribute set to message, and an input text element with the id set to userInput. <body onload="onLoad()"> <div id="message"></div> <input type="text" id="userInput" /> </body> When we run the application on the device, the initial output would provide the user with an input box to enter text, should they wish to, as shown in the following screenshot: If we were to pause the application and then resume it after a period of time, the display would then update to look something like the following screenshot: How it works... We set up the deviceready event listener after the DOM was fully loaded, which would then run the onDeviceReady function. Within this method we then added two new event listeners to catch the pause and resume events respectively. When the application is paused and placed into the background processes on the device, we saved the current date and time into a global variable. We also checked for the existence of any user-supplied input and if it was present we saved it using the localStorage capabilities on the device. When the application was resumed and placed back into the foreground on the device, the onResume method was run, which obtained the time difference between the saved and current datetime values to output to the user. We also retrieved the saved user input from the localStorage if we had set it within the onPause method. To find out more about the resume event, please refer to the official documentation, available here: http://docs.phonegap.com/en/2.0.0/cordova_events_events.md.html#resume.
Read more
  • 0
  • 0
  • 3058

article-image-adding-worksheets-and-resources-moodle
Packt
27 Oct 2009
12 min read
Save for later

Adding Worksheets and Resources with Moodle

Packt
27 Oct 2009
12 min read
We're teaching the topic of Rivers and Flooding; so to start with, we'll need to introduce our class to some basic facts about rivers and how they work. We aren't going to generate any new stuff yet; we're just going to upload to Moodle what we have already produced in previous years. Putting a worksheet on Moodle The way Moodle works is that we must first upload our worksheet into the course file storage area. Then, in that central section of our course page, we make a link to the worksheet from some appropriately chosen words. Our students click on these words to get to the worksheet. We've got an introductory factsheet (done in Word) about the River Thames. Let's get it into Moodle: Time for action-uploading a factsheet on to Moodle We need to get the worksheet uploaded into Moodle. To get this done, we have to follow a few simple steps. Go to your course page and click on the Turn editing on button, as shown in the following screenshot: Don't worry about all of the new symbols (icons) that appear. In the section you want the worksheet to be displayed, so look for these two boxes: Click on the Add a resource box (I'll go through all its options when we have a recap, later). Select a link to a file or web site. In Name, type the text that you want the students to click on, and in Summary (if you want) add a short description. The following screenshot gives an example of this: Once you're done with the above steps, click on Choose or upload a file. This takes you to the course files storage area. Click on Make a folder, and in the dialog box that is displayed, choose a suitable name for the folder all your worksheets will be stored in (we'll use Worksheets). Click on Create. Click on the folder that you just created (It will be empty except for Parent Folder, which takes you back to the main course files). Click on Upload a file. You'll be prompted to browse your computer's hard drive for the worksheet. Find the worksheet, select it with your cursor and click Open. It will appear as shown in the following screenshot: Click Upload this file. Once the file has been uploaded, it will appear as shown in the following screenshot: What just happened? We just uploaded our first ever worksheet to Moodle. It's now in the course files. Next, we need to make a link on the page that students can click on to get to that worksheet. I know what you're thinking! Thirteen steps, and there's still no sign of our River Thames worksheet on the course page in Moodle. Is it going to be this long-winded every time? Don't worry! There are only two—at worst three—steps left . And although it seems to be a lot of effort the first time, it gets much quicker, as we move on. We are also trying to be organized from the start by putting our worksheets neatly into a folder, so we took a couple of extra steps that we won't have to do next time. The folder will already be there for us. Ofcourse, you can just click on Upload a file and get your worksheets straight into the course files without any sort of order, and they will display for your students just as well. But when you have a lot of worksheets loaded, it will become harder and harder to locate them unless you have a system. Time for action-displaying our factsheet on our course page To get the Moodle course started, we need to create a link that—when clicked, will get the course started, carrying on from where we left off : Click on the word Choose to the right of your worksheet. (We are choosing to put this on Moodle.) The River Thames worksheet now shows in the Location box, under Link to a file or web site. We are almost there! Scroll down and make sure that you have selected the New window option in theWindow box, as shown in the following screenshot: At the bottom of the screen, click on Save and return to course. Done! The option Search for web page would take you to Google or another search engine to find a web site. You could put that web site into the location box instead, and it would make a clickable link for your students to follow. What just happened? Congratulations! You’ve now made a link to the factsheet about the River Thames that will get our Rivers and Flooding course started! By doing the final step above, we will get taken back to the course page where we'll see the words that we wrote in the Name box. They'll be in blue with a line underneath. This tells us it's a clickable link that will take us to the factsheet. If you can do that once, you can do it many times. Have a go hero-putting a slideshow onto Moodle It's important to go through the steps again, pretty quickly, so that you become familiar with them and are able to speed the process up. So why not take one of your slide shows (maybe done in PowerPoint) and upload that to Moodle? Start by creating a folder called Slideshows, so that in future, it will be available for any slideshows that you upload. Or, if you're too tired, just upload another sheet into our Worksheets folder and display that.   Putting a week's worth of slideshows into Moodle Now let's suppose that we have already prepared a week's worth of slideshows. Actually, I could say, a month's worth of worksheets, or a year's worth of exam papers. Basically, what we're going to do is upload several items, all at once. This is very useful because once you get used to uploading and displaying worksheets, you will very quickly start thinking about how tedious it would be, to put them on Moodle one at a time. Especially if you are studying ten major world rivers, and you have to go through all of those steps ten times. Well, you don't! Let's use my River Processes slideshows as our example. I have them saved in a folder on My Computer (as opposed to being shoved at random in a drawer, obviously!). Under normal circumstances, Moodle won't let you upload whole folders just like that. You have to either compress or zip them first (that basically means squeeze it up a bit, so it slides into cyberspace more smoothly). We first need to leave Moodle for a while and go to our own computer. I'm using Windows; for Macs, it will be slightly different. Time for action-getting a whole folder of work into Moodle in one go To view the slideshows, we need to upload the folder containing them from the hard drive of our computer into Moodle. Find the folder that you want to upload, right-click on it, and select Compressed (zipped) Folder within the Send To option. You'll get another folder with the same name, but in ZIP format. Go to your Moodle course page, and in the Administration box, click Files. We're in the course files storage area—this is another way in, if you ever need one! You can upload anything straight into here, and then provide a link to a file or web site. As we have done before, click on Upload and upload the zipped folder (it ends in .zip). Now click on Unzip, which is displayed to the right of your folder name (as shown in the following screenshot), and the folder will be restored to its normal size. What just happened? We put a bunch of slideshows about how rivers work into a folder on our computer. We then zipped the folder to make it slide into Moodle, and then when it was uploaded, we unzipped it to get it back to normal. If you want to be organized, select the checkbox displayed to the left of the zipped folder, and select delete completely. We don't need the zipped folder now, as we have got the original folder back. We now have two choices. Using the Link to a file or web site option in the Add a resource block, we can display each slideshow, in an orderly manner, in the list. We did this with our Thames factsheet, so we know how to do this. Alternatively, we can simply display the folder and let the students open it to get to the slideshows. We're going to opt for the second choice. Why? Bearing in mind about appearances being vital, it would look much neater on our course page if we had a dinky little briefcase icon. The student can click on the briefcase icon to see the list of slideshows, rather than scrolling down a long list on the page. Let us see how this is done: Time for action-displaying a whole folder on Moodle Let us upload the entire folder, which contains the related slideshows, onto Moodle. This will require us to perform only four steps: With editing turned on, click on Add a resource and choose Display a directory. In the Name field, type something meaningful for the students to click on and add a description in the Summary field, if you wish. Click on Display a directory and find the one that you want—for us, RiverProcesses. Scroll down, and click on Save and return to course. What just happened? We made a link to a week's worth of slideshows on our course page, instead of displaying them one at a time. If we looked at the outcome, instead of the icon of a slideshow, such as the PowerPoint icon, we get a folder icon. When the text next to it is clicked, the folder opens, and all of the slideshows inside can be viewed. It is much easier on the eye, when you go directly to the course page, than going through a long list of stuff . Making a 'click here' type link to the River Thames web site Let's learn how to create a link that will lead us to the River Thames web site, or in fact to any web site. However, we're investigating the Thames at the moment, so this would be really helpful. Just imagine, how much simpler it would be for our students to be able to get to a site in one click, rather than type it by hand, spell it wrong, and have it not work. The way we will learn now is easy. In fact, it's so easy that you could do it yourself with only one hint from me. Have a go hero-linking to a web site Do you recollect that we uploaded our worksheet and used Link to a file or web site? We linked it to a file (our worksheet). Here, you just need to link to a web site, and everything else is just the same. When you get to the Link to a file or web site box, instead of clicking Choose or upload a file…, just type in, or copy and paste, the web site that you want to link to (making sure you include only one http://). Remember that we saw earlier, that if you click on Search for web page…, it will take you to Google or some other Search Engine web page to find you a web site that you'd like to link to. The following screenshot shows how to link a file or web site into our Moodle course : That's it! Try it! Go back to your course page; click on the words that you specified as the Name for the web page link, and check whether it works. It should open the web page in a new window, so that once finished, our students can click on the X to close the site and will still have Moodle running in the background. Recap—where do we stand now? We have learnt a lot of interesting things so far. Lets just have a recap of the things that we have learned so far. We have learnt to: Upload and display individual worksheets (as we've worked on the River Thames) Upload and display whole folders of worksheets (as we did with the River Processes slideshows folder) Make a click here type link to any web site that we want, so that our students will just need to click on this link to get to that web site We're now going to have a break from filling up our course for a while, and take a step to another side. Our first venture into Moodle's features was the Link to a file or web site option, but there are many more yet to be investigated. Let's have a closer look at those Add a resource… options in the following screenshot, so that we know, where we are heading: The table below shows all of the Add a Resource… options. What are they, which is the one we need, and what can we safely ignore? You might recognize one or two already. We shall meet the others in a moment.
Read more
  • 0
  • 0
  • 3055

article-image-windows-azure-mobile-services-implementing-push-notifications-using
Packt
13 Jan 2014
8 min read
Save for later

Windows Azure Mobile Services - implementing push notifications

Packt
13 Jan 2014
8 min read
Understanding Push Notification Service flow The following procedure illustrates Push Notification Service (PNS) flow from establishing a channel to receiving a notification: The mobile device establishes a channel with the PNS and retrieves its handle (URI). The device registers its handle with a backend service (in our case, a table in our Mobile Service). A notification request can be made by another service, an admin system, and so on, which calls the backend service (in our case, an API). The service makes a request to the correct PNS for every device handle. The PNS notifies the device. Setting up Windows Store apps Visual Studio 2013 has a new wizard, which associates the app with the store in order to obtain a push notifications URI. Code is added to the app to interact with the service that will be updated to have a Channels table. This table has an Insert script to insert the channel and ping back a toast notification upon insert. The following procedure takes us through using the wizard to add a push channel to our app: Right-click on the project, and then navigate to Add | Push Notification. Follow the wizard and sign in to your store account (if you haven't got one, you will need to create one). Reserve an app name and select it. Then, continue by clicking on Next. Click on Import Subscriptions... and the Import Windows Azure Subscriptions dialog box will appear. Click on Download subscription file. Your default browser will be launched and the subscriptions file will be automatically downloaded. If you are logged into the portal, this will happen automatically; otherwise, you'll be prompted to log in. Once the subscription file is downloaded, browse to the downloaded file in the Import Windows Azure Subscriptions dialog box and click on Import. Select the subscription you wish to use, click on Next, and then click on Finish in the final dialog box. In the Output window in Visual Studio, you should see something like the following: Attempting to install 'WindowsAzure.MobileServices' Successfully installed NuGet Package 'WindowsAzure.MobileServices' Successfully added 'push.register.cs' to the project Added field to the App class successfully Initialization code was added successfully Updated ToastCapable in the app manifest Client Secret and Package SID were updated successfully on the Windows Azure Mobile Services portal The 'channels' table and 'insert.js' script file were created successfully Successfully updated application redirect domain Done We will now see a few things have been done to our project and service: The Package.StoreAssociation.xml file is added to link the project with the app on the store. Package.appxmanifest is updated with the store application identity. Add a push.register.cs class in servicesmobile services[Your Service Name], which creates a push notifications channel and sends the details to our service. The server explorer launches and shows us our service with a newly created table named channels, with an Insert method that inserts or updates (if changed) our channel URI. Then, it sends us a toast notification to test that everything is working. Run the app and check that the URI is inserted into the table. You will get a toast notification. Once you've done this, remove the sendNotifications(item.channelUri); call and function from the Insert method. You can do this in Visual Studio via the Server Explorer console. I've modified the script further to make sure the item is always updated, so when we send push notifications, we can send them to URIs that have been recently updated so that we are targeting users who are actually using the application (channels actually expire after 30 days too, so it would be a waste of time trying to push to them). The following code details these modifications: function insert(item, user, request) { var ct = tables.getTable("channels"); ct.where({ installationId: item.installationId }).read({ success: function (results) { if (results.length > 0) { // always update so we get the updated date var existingItem = results[0]; existingItem.channelUri = item.channelUri; ct.update(existingItem, { success: function () { request.respond(200, existingItem); } }); } else { // no matching installation, insert the record request.execute(); } } }) } I've also modified the UploadChannel method in the app so that it uses a Channel model that has a Platform property. Therefore, we can now work out which PNS provider to use when we have multiple platforms using the service. The UploadChannel method also uses a new InsertChannel method in our DataService method (you can see the full code in the sample app). The following code details these modifications: public async static void UploadChannel() { var channel = await Windows.Networking.PushNotifications. PushNotificationChannelManager. CreatePushNotificationChannelForApplicationAsync(); var token = Windows.System.Profile.HardwareIdentification. GetPackageSpecificToken(null); string installationId = Windows.Security.Cryptography. CryptographicBuffer.EncodeToBase64String(token.Id); try { var service = new DataService(); await service.InsertChannel(new Channel() { ChannelUri = channel.Uri, InstallationId = installationId, Platform = "win8" }); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); } }  Setting up tiles To implement wide or large square tiles, we need to create the necessary assets and define them in the Visual Assets tab of the Package.appxmanifest editor. This is shown in the following screenshot:  Setting up badges Windows Store apps support badge notifications as well as tile and toast. However, this requires a slightly different configuration. To implement badge notifications, we perform the following steps: Create a 24 x 24 pixel PNG badge that can have opacity, but must use only white color. Define the badge in the Badge Logo section of the Visual Assets tab of the Package.appxmanifest editor. Add a Background Tasks declaration in the Declarations tab of the Package.appxmanifest editor, select Push notification, and enter a Start page, as shown in the following screenshot: Finally, in the Notifications tab of the Package.appxmanifest editor, set Lock screen notifications to Badge. This is shown in the following screenshot: To see the badge notification working, you also need to add the app to the lock screen badge slots in Lock Screen Applications | Change PC Settings | Lock Screen.  Setting up Windows Phone 8 apps Visual Studio 2012 Express for Windows Phone doesn't have a fancy wizard like Visual Studio 2013 Express for Windows Store. So, we need to configure the channel and register it with the service manually. The following procedure sets up the notifications in the app by using the table that we created in the preceding Setting up Windows Store apps section: Edit the WMAppManifest.xml file to enable ID_CAP_IDENTITY_DEVICE, which allows us to get a unique device ID for registering in the Channels table, and ID_CAP_PUSH_NOTIFICATION, which allows push notifications in the app. These options are available in the Capabilities tab, as shown in the following screenshot: To enable wide tiles, we need to check Support for large Tiles (you can't see the tick unless you hover over it, as there is apparently a theming issue in VS!) and pick the path of the wide tile we want to use (by default, there is one named FlipCycleTileLarge.png under Tiles in the Assets folder). This is shown in the following screenshot: Next, we need to add some code to get the push channel URI and send it to the service: using Microsoft.Phone.Info; using Microsoft.Phone.Notification; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using TileTapper.DataServices; using TileTapper.Models; namespace TileTapper.Helpers { public class ChannelHelper { // Singleton instance public static readonly ChannelHelper Default = new ChannelHelper(); // Holds the push channel that is created or found private HttpNotificationChannel _pushChannel; // The name of our push channel private readonly string CHANNEL_NAME = "TileTapperPushChannel"; private ChannelHelper() { } public void SetupChannel() { try { // Try to find the push channel this._pushChannel = HttpNotificationChannel.Find(CHANNEL_NAME); // If the channel was not found, then create a new // connection to the push service if (this._pushChannel == null ) { this._pushChannel = new HttpNotificationChannel(CHANNEL_NAME); this.AttachEvents(); this._pushChannel.Open(); // Bind channel for Tile events this._pushChannel.BindToShellTile(); // Bind channel for Toast events this._pushChannel.BindToShellToast(); } else this.AttachEvents(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); } } private void AttachEvents() { // Register for all the events before attempting to // open the channel this._pushChannel.ChannelUriUpdated + = async (s, e) => { // Register URI with service await this.Register(); }; this._pushChannel.ErrorOccurred += (s, e) => { System.Diagnostics.Debug.WriteLine(e.ToString()); }; } private async Task Register() { try { var service = new DataService(); await service.InsertChannel(new Channel() { ChannelUri = this._pushChannel.ChannelUri.AbsoluteUri, InstallationId = this.GetDeviceUniqueName(), Platform = "wp8" }); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); } } // Note: to get a result requires // ID_CAP_IDENTITY_DEVICE // to be added to the capabilities of the WMAppManifest // this will then warn users in marketplace private byte[] GetDeviceUniqueID() { byte[] result = null; object uniqueId; if (DeviceExtendedProperties.TryGetValue("DeviceUniqueId", out uniqueId)) result = (byte[])uniqueId; return result; } private string GetDeviceUniqueName() { byte[] id = this.GetDeviceUniqueID(); string idEnc = Encoding.Unicode.GetString(id, 0, id.Length); string deviceID = HttpUtility.UrlEncode(idEnc); return deviceID; } } } This is a singleton class that holds an instance of the HttpNotificationChannel object, so that channel URI changes can be captured and sent up to our service. The two methods at the end of the code snippet, GetDeviceUniqueID and GetDeviceUniqueName, will give a unique device identifier for the channels table. Now that we have the code to manage the channel, we need to call the SetupChannel method in the App.xaml.cs launching method as shown in the following code snippet: private void Application_Launching(object sender, LaunchingEventArgs e) { TileTapper.Helpers.ChannelHelper.Default.SetupChannel(); }
Read more
  • 0
  • 0
  • 3052
article-image-unittest-python
Packt
21 Jan 2010
11 min read
Save for later

Unittest in Python

Packt
21 Jan 2010
11 min read
So let's get on with it! Basic unittest Before we start talking about new concepts and features, let's take a look at how to use unittest to express the ideas that we've already learned about. That way, we'll have something solid to ground our new understanding into. Time for action – testing PID with unittest We'll visit the PID class (or at least the tests for the PID class). We'll write the tests so that they operate within the unittest framework. We'll be implementing the tests using the unittest framework. Create a new file called test_pid.py in the same directory as pid.py. Notice that this is a .py file: unittest tests are pure python source code, rather than being plain text with source code embedded in it. That means the tests will be less useful from a documentary point of view, but grants other benefits in exchange. Insert the following code into your newly-created test_pid.py (and please note that a few lines are long enough to get wrapped on the article's page): from unittest import TestCase, mainfrom mocker import Mockerimport pidclass test_pid_constructor(TestCase): def test_without_when(self): mocker = Mocker() mock_time = mocker.replace('time.time') mock_time() mocker.result(1.0) mocker.replay() controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12) mocker.restore() mocker.verify() self.assertEqual(controller.gains, (0.5, 0.5, 0.5)) self.assertAlmostEqual(controller.setpoint[0], 0.0) self.assertEqual(len(controller.setpoint), 1) self.assertAlmostEqual(controller.previous_time, 1.0) self.assertAlmostEqual(controller.previous_error, -12.0) self.assertAlmostEqual(controller.integrated_error, 0) def test_with_when(self): controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=1, initial=12, when=43) self.assertEqual(controller.gains, (0.5, 0.5, 0.5)) self.assertAlmostEqual(controller.setpoint[0], 1.0) self.assertEqual(len(controller.setpoint), 1) self.assertAlmostEqual(controller.previous_time, 43.0) self.assertAlmostEqual(controller.previous_error, -11.0) self.assertAlmostEqual(controller.integrated_error, 0)class test_calculate_response(TestCase): def test_without_when(self): mocker = Mocker() mock_time = mocker.replace('time.time') mock_time() mocker.result(1.0) mock_time() mocker.result(2.0) mock_time() mocker.result(3.0) mock_time() mocker.result(4.0) mock_time() mocker.result(5.0) mocker.replay() controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12) self.assertEqual(controller.calculate_response(6), -3) self.assertEqual(controller.calculate_response(3), -4.5) self.assertEqual(controller.calculate_response(-1.5), -0.75) self.assertEqual(controller.calculate_response(‑2.25), ‑1.125) mocker.restore() mocker.verify() def test_with_when(self): controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12, when=1) self.assertEqual(controller.calculate_response(6, 2), -3) self.assertEqual(controller.calculate_response(3, 3), -4.5) self.assertEqual(controller.calculate_response(‑1.5, 4), ‑0.75) self.assertEqual(controller.calculate_response(‑2.25, 5), ‑1.125)if __name__ == '__main__': main() Run the tests by typing: $ python test_pid.py What just happened? Let's go through the code section and see what each part does. After that, we'll talk about what it all means when put together. from unittest import TestCase, mainfrom mocker import Mockerimport pidclass test_pid_constructor(TestCase): def test_without_when(self): mocker = Mocker() mock_time = mocker.replace('time.time') mock_time() mocker.result(1.0) mocker.replay() controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12) mocker.restore() mocker.verify() self.assertEqual(controller.gains, (0.5, 0.5, 0.5)) self.assertAlmostEqual(controller.setpoint[0], 0.0) self.assertEqual(len(controller.setpoint), 1) self.assertAlmostEqual(controller.previous_time, 1.0) self.assertAlmostEqual(controller.previous_error, -12.0) self.assertAlmostEqual(controller.integrated_error, 0) After a little bit of setup code, we have a test that the PID controller works correctly when not given a when parameter. Mocker is used to replace time.time with a mock that always returns a predictable value, and then we use several assertions to confirm that the attributes of the controller have been initialized to the expected values. def test_with_when(self): controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=1, initial=12, when=43) self.assertEqual(controller.gains, (0.5, 0.5, 0.5)) self.assertAlmostEqual(controller.setpoint[0], 1.0) self.assertEqual(len(controller.setpoint), 1) self.assertAlmostEqual(controller.previous_time, 43.0) self.assertAlmostEqual(controller.previous_error, -11.0) self.assertAlmostEqual(controller.integrated_error, 0) This test confirms that the PID constructor works correctly when the when parameter is supplied. Unlike the previous test, there's no need to use Mocker, because the outcome of the test is not supposed to be dependant on anything except the parameter values—the current time is irrelevant. class test_calculate_response(TestCase): def test_without_when(self): mocker = Mocker() mock_time = mocker.replace('time.time') mock_time() mocker.result(1.0) mock_time() mocker.result(2.0) mock_time() mocker.result(3.0) mock_time() mocker.result(4.0) mock_time() mocker.result(5.0) mocker.replay() controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12) self.assertEqual(controller.calculate_response(6), -3) self.assertEqual(controller.calculate_response(3), -4.5) self.assertEqual(controller.calculate_response(-1.5), -0.75) sel+f.assertEqual(controller.calculate_response(‑2.25), ‑1.125) mocker.restore() mocker.verify() The tests in this class describe the intended behavior of the calculate_response method. This first test checks the behavior when the optional when parameter is not supplied, and mocks time.time to make that behavior predictable. def test_with_when(self): controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12, when=1) self.assertEqual(controller.calculate_response(6, 2), -3) self.assertEqual(controller.calculate_response(3, 3), -4.5) self.assertEqual(controller.calculate_response(‑1.5, 4), ‑0.75) self.assertEqual(controller.calculate_response(‑2.25, 5), ‑1.125) In this test, the when parameter is supplied, so there is no need to mock time.time. We just have to check that the result is what we expected. The actual tests that we performed are the same ones that were written in the doctest. So far, all that we see is a different way of expressing them. The first thing to notice is that the test file is divided up into classes that inherit from unittest.TestCase, each of which contains one or more test methods. The name of each test method begins with the word test, which is how unittest recognizes that they are tests. Each test method embodies a single test of a single unit. This gives us a convenient way to structure our tests, grouping together related tests into the same class, so that they're easier to find. Putting each test into its own method means that each test executes in an isolated namespace, which makes it somewhat easier to keep unittest‑style tests from interfering with each other, relative to doctest‑style tests. It also means that unittest knows how many unit tests are in your test file, instead of simply knowing how many expressions there are (you may have noticed that doctest counts each >>> line as a separate test). Finally, putting each test in its own method means that each test has a name, which can be a valuable feature. Tests in unittest don't directly care about anything that isn't part of a call to one of the assert methods of TestCase. That means that when we're using Mocker, we don't have to be bothered about the mock objects that get returned from demonstration expressions, unless we want to use them. It also means that we need to remember to write an assert describing every aspect of the test that we want to have checked. We'll go over the various assertion methods of TestCase shortly. Tests aren't of much use, if you can't execute them. For the moment, the way we'll be doing that is by calling unittest.main when our test file is executed as a program by the Python interpreter. That's about the simplest way to run unittest code, but it's cumbersome when you have lots of tests spread across lots of files. if __name__ == '__main__': might look strange to you, but its meaning is fairly straight forward. When Python loads any module, it stores that module's name in a variable called __name__ within the module (unless the module is the one passed to the interpreter on the command line). That module always gets the string '__main__' bound to its __name__ variable. So, if __name__ == '__main__': means—if this module was executed directly from the command line. Assertions Assertions are the mechanism that we use to tell unittest what the important outcomes of the test are. By using appropriate assertions, we can tell unittest exactly what to expect from each test. assertTrue When we call self.assertTrue(expression), we're telling unittest that the expression must be true in order for the test to be a success. This is a very flexible assertion, since you can check for nearly anything by writing the appropriate boolean expression. It's also one of the last assertions you should consider using, because it doesn't tell unittest anything about the kind of comparison you're making, which means that unittest can't tell you as clearly what's gone wrong if the test fails. For an example of this, consider the following test code which contains two tests that are guaranteed to fail: from unittest import TestCase, mainclass two_failing_tests(TestCase): def test_assertTrue(self): self.assertTrue(1 == 1 + 1) def test_assertEqual(self): self.assertEqual(1, 1 + 1)if __name__ == '__main__': main() It might seem like the two tests are interchangeable, since both test the same thing. Certainly they'll both fail (or in the unlikely event that one equals two, they'll both pass), so why prefer one over the other? Take a look at what happens when we run the tests (and also notice that the tests were not executed in the same order as they were written; tests are totally independent of each other, so that's okay, right?): Do you see the difference? The assertTrue test was able to correctly determine that the test should fail, but it didn't know enough to report any useful information about why it failed. The assertEqual test, on the other hand, knew first of all that it was checking that two expressions were equal, and second it knew how to present the results, so that they would be most useful: by evaluating each of the expressions that it was comparing and placing a != symbol between the results. It tells us both what expectation failed, and what the relevant expressions evaluate to. assertFalse The assertFalse method will succeed when the assertTrue method would fail, and vice versa. It has the same limits in terms of producing useful output that assertTrue has, and the same flexibility in terms of being able to test nearly any condition. assertEqual As mentioned in the assertTrue discussion, the assertEqual assertion checks that its two parameters are in fact equal, and reports a failure if they are not, along with the actual values of the parameters. assertNotEqual The assertNotEqual assertion fails whenever the assertEqual assertion would have succeeded, and vice versa. When it reports a failure, its output indicates that the values of the two expressions are equal, and provides you with those values. assertAlmostEqual As we've seen before, comparing floating point numbers can be troublesome. In particular, checking that two floating point numbers are equal is problematic, because things that you might expect to be equal—things that, mathematically, are equal—may still end up differing down among the least significant bits. Floating point numbers only compare equal when every bit is the same. To address that problem, unittest provides assertAlmostEqual, which checks that two floating point values are almost the same; a small amount of difference between them is tolerated. Lets look at this problem in action. If you take the square root of 7, and then square it, the result should be 7. Here's a pair of tests that check that fact: from unittest import TestCase, mainclass floating_point_problems(TestCase): def test_assertEqual(self): self.assertEqual((7.0 ** 0.5) ** 2.0, 7.0) def test_assertAlmostEqual(self): self.assertAlmostEqual((7.0 ** 0.5) ** 2.0, 7.0) if __name__ == '__main__': main() The test_assertEqual method checks that , which is true in reality. In the more specialized number system available to computers, though, taking the square root of 7 and then squaring it doesn't quite get us back to 7, so this test will fail. More on that in a moment. Test test_assertAlmostEqual method checks that , which even the computer will agree is true, so this test should pass. Running those tests produces the following, although the specific number that you get back instead of 7 may vary depending on the details of the computer the tests are being run on: Unfortunately, floating point numbers are not precise, because the majority of numbers on the real number line can not be represented with a finite, non-repeating sequence of digits, much less a mere 64 bits. Consequently, what you get back from evaluating the mathematical expression is not quite 7. It's close enough for government work though—or practically any other sort of work as well—so we don't want our test to quibble over that tiny difference. Because of that, we should use assertAlmostEqual and assertNotAlmostEqual when we're comparing floating point numbers for equality. This problem doesn't generally carry over into other comparison operators. Checking that one floating point number is less than the other, for example, is very unlikely to produce the wrong result due to insignificant errors. It's only in cases of equality that this problem bites us.
Read more
  • 0
  • 0
  • 3050

article-image-html5-developing-rich-media-applications-using-canvas
Packt
19 May 2011
10 min read
Save for later

HTML5: Developing Rich Media Applications using Canvas

Packt
19 May 2011
10 min read
HTML5 Multimedia Development Cookbook Recipes for practical, real-world HTML5 multimedia driven development. The cool thing with the new open-source canvas element is that not only can you create dynamic images on the fly, but the users' actions can create new images in real time as well—all without requiring a plugin. Sounds great, right? In many ways it is, but it also leaves our friends using assistive technologies out in the cold. What will happen if you're using a browser that doesn't support the new canvas element? Pretty much nothing. The browser just won't display it. That's why you'll need to be especially careful with this technology and not place anything inside the new canvas element on which your site or application absolutely depends. You must also consider fallback content. Browsers that support canvas include: Before proceeding with developing with the new canvas element, make sure you have a good foundation of skills with HTML and JavaScript. Being comfortable with object-oriented programming sure wouldn't hurt either. Now, let's get cooking! Setting up the canvas environment Creating the new canvas element is easy. How to do it... Check out how simple this is: <!DOCTYPE html> <html> <head> <title>Canvas</title> <meta charset="utf-8" /> </head> <body> <canvas id="FirstCanvas" width="800" height="600"> <!-- Fallback code goes here --> </canvas> </body> </html> How it works... Of course, we can use whatever height and width dimensions we need, but that simple set of tags is what we need to start. You're probably thinking we could use CSS to control the height and width, but resist that temptation. Because the new canvas element contains a 2d rendering context, that approach can cause unpredictable behavior. There's more... Next, we'll call the new canvas element JavaScript API while calling jQuery: <!DOCTYPE html> <html> <head> <title>Canvas</title> <meta charset="utf-8" /> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/ jquery.min.js"></script> <script> $(document).ready(function() { var canvas = document.getElementById("FirstCanvas"); var ctx = canvas.getContext("2d"); }); </script> </head> <body> <canvas id="FirstCanvas" width="800" height="600"> <!-- Fallback code goes here --> </canvas> </body> </html> He's smart "Let me make one thing completely clear: When you use canvas, you're not drawing on the canvas element itself. Instead, you're actually drawing on the 2d rendering context, which you're accessing through the canvas element via the JavaScript API." – Rob Hawkes What am I sayin'? Apple first introduced the new canvas element for the OSX Dashboard years ago. It was later implemented in web browsers Safari and then Chrome, with other browsers following suit. Since then it's become an official part of the HTML5 specification. What's next for <canvas>? Right now, we're barely scratching the surface of what the new canvas element can do. Now and in the future we'll use it to create animations, charts, diagrams, drawing apps, graphs, and user interfaces. What will you dream up? See also Developer Martin Angelov penned a great how-to guide titled, "An HTML5 Slideshow w/Canvas & jQuery" for Tutorial Zine at: http://tutorialzine.com/2010/09/html5-canvas-slideshow-jquery. In it, Martin demonstrates how to combine the new canvas element with jQuery, the most popular JavaScript framework, to create an intensely interactive image slideshow. Understanding the 2d rendering context It's important to understand that the new canvas element is really a "surface" on which to draw bitmapped images in the browser. How to do it... Defining a canvas tag like this only tells half the story: <!DOCTYPE html> <html> <head> <title>Canvas</title> <meta charset="utf-8" /> </head> <body> <canvas id="FirstCanvas" width="800" height="600"> <!-- Fallback code goes here --> </canvas> </body> </html> How it works... By itself that HTML5 code does nothing. We have to use JavaScript to make the Document Object Model retrieve the 2d rendering context in order to get something to happen: <script> $(document).ready(function() { var canvas = document.getElementById("FirstCanvas"); var ctx = canvas.getContext("2d"); }); </script> To be fair, that bit of JavaScript won't do anything without the canvas tag in the HTML either. There's more... You may be wondering about the name. If there's a 2d rendering context, isn't there probably a 3d rendering context too? The short answer is yes. But the more detailed answer isn't so simple. While a 3d rendering context does exist in theory, at the time of this publication no browser supports it. So if the new canvas element renders in 3d but nobody sees it, did it really do anything? You can master <canvas> The 2d context uses a number of different drawing contexts for the new canvas element that use syntaxes that should look quite familiar if you're experienced with CSS and JavaScript. X, meet Y When drawing, remember the X and Y axis in the top left corner of your browser window. Values increase going down the page. Respect my authority! The World Wide Web Consortium's HTML5 Canvas 2d Context specification is online at: http://dev.w3.org/html5/2dcontext. There we can dig even deeper into information like conformance requirements, the canvas state, transformations, compositing, colors and styles, line styles, shadows, simple shapes, complex shapes, focus management, text, images, pixel manipulation, drawing model, examples, and more. Processing shapes dynamically Let's look at the JavaScript functions that allow the new canvas element to draw rectangles. How to do it... fillRect(x,y,width,height) strokeRect(x,y,width,height) In order: fillRect(x,y,width,height) draws a filled rectangle. Next, strokeRect(x,y,width,height) draws an outline around the rectangle. Now, let's draw some shapes. How it works... We'll start with our basic canvas code and incorporate our new functions: <!DOCTYPE html> <html> <head> <title>Canvas</title> <meta charset="utf-8" /> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/ jquery.min.js"></script> <script> $(document).ready(function() { var canvas = document.getElementById("FirstCanvas"); var ctx = canvas.getContext("2d"); ctx.strokeRect(10, 10, 396, 236); ctx.fillStyle = "red"; ctx.fillRect(11, 11, 100, 100); ctx.fillStyle = "white"; ctx.fillRect(111, 11, 34, 100); ctx.fillStyle = "red"; ctx.fillRect(156, 11, 249, 100); ctx.fillStyle = "white"; ctx.fillRect(11, 111, 394, 34); ctx.fillStyle = "red"; ctx.fillRect(11, 145, 100, 100); ctx.fillStyle = "white"; ctx.fillRect(111, 145, 34, 100); ctx.fillStyle = "red"; ctx.fillRect(156, 145, 249, 100); }); </script> </head> <body> <canvas id="FirstCanvas" width="416" height="256"> <p>Flag of Denmark</p> </canvas> </body> </html> What we've created resembles the flag of Denmark! There's more... This example may not seem overwhelming at first, but when you remember that we've created an image with hardly any HTML and no CSS whatsoever, the new canvas element starts to look pretty impressive. Any way you want it Note that while we used color names ("white" and "red") we could also use hexadecimal values or RGB or even HSL! Use whatever makes the most sense for you and your interactive project. Similar to tables? Think of the color and size specifications for this example almost as the old-school tables we used to build back in the day for layout. While certainly not the same, there are definitely similarities to that technique in this case. Be a square first Mastering rectangles is the first canvas technique that's important to have under your belt after the ability to set up the element itself. Understanding the basics of this approach will help you grasp the fundamentals of the next few recipes. Drawing borders for images using canvas Let's take a closer look at the super simple method of drawing borders around images using the new canvas element. How to do it... First, we'll start with our basic canvas code and add one new line to draw a border: <!DOCTYPE html> <html> <head> <title>Canvas</title> <meta charset="utf-8" /> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/ jquery.min.js"></script> <script> $(document).ready(function() { var canvas = document.getElementById("FirstCanvas"); var ctx = canvas.getContext("2d"); ctx.strokeRect(10, 20, 100, 100); }); </script> </head> <body> <canvas id="FirstCanvas" width="800" height="600"> <!-- Fallback code goes here --> </canvas> </body> </html> How it works... That one line of JavaScript tells the browser to create a rectangle starting at 10 pixels from the left and 20 pixels from the top of the new canvas element. It draws the box 100 pixels square. There's more... That's nice, but if we want the border to be any other color than the default, we'll need to specify that: <!DOCTYPE html> <html> <head> <title>Canvas</title> <meta charset="utf-8" /> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/ jquery.min.js"></script> <script> $(document).ready(function() { var canvas = document.getElementById("myCanvas"); var ctx = canvas.getContext("2d"); ctx.strokeStyle = "rgb(0, 128, 0)"; ctx.strokeRect(10, 20, 100, 100); }); </script> </head> <body> <canvas id="myCanvas" width="600" height="600"> <!-- Fallback code goes here --> </canvas> </body> </html> In this case we've used strokeStyle to specify an RGB color of pure green. Style first If you plan to style a border, you'll need to specify that before the border is drawn by the browser. If you specify that style afterward, the browser will simply ignore it. Many color values work The style attribute we just used was RGB, but the method also works with colors ("green", for example), hexadecimal values, HSL, and RGBA. I like big borders and I cannot lie If no border width is specified, the browser will automatically draw a one-pixel border. Here's how to change that: <!DOCTYPE html> <html> <head> <title>Canvas</title> <meta charset="utf-8" /> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/ jquery.min.js"></script> <script> $(document).ready(function() { var canvas = document.getElementById("myCanvas"); var ctx = canvas.getContext("2d"); ctx.lineWidth = 10; ctx.strokeStyle = "rgb(0, 128, 0)"; ctx.strokeRect(10, 20, 100, 100); }); </script> </head> <body> <canvas id="myCanvas" width="600" height="600"> <!-- Fallback code goes here --> </canvas> </body> </html> It's just this easy:  
Read more
  • 0
  • 0
  • 3048

article-image-unlocking-javascript-core
Packt
16 Feb 2016
19 min read
Save for later

Unlocking the JavaScript Core

Packt
16 Feb 2016
19 min read
You may have owned an iPhone for years and regard yourself as an experienced user. At the same time, you keep removing unwanted characters one at a time while typing by pressing delete. However, one day you find out that a quick shake allows you to delete the whole message in one tap. Then you wonder why on earth you didn't know this earlier. The same thing happens with programming. We can be quite satisfied with our coding until, all of sudden, we run into a trick or a lesser-known language feature that makes us reconsider the entire work done over the years. It turns out that we could do this in a cleaner, more readable, more testable, and more maintainable way. So it's presumed that you already have experience with JavaScript; however, this article equips you with the best practices to improve your code. (For more resources related to this topic, see here.) We will cover the following topics: Making your code readable and expressive Mastering multiline strings in JavaScript Manipulating arrays in the ES5 way Traversing an object in an elegant, reliable, safe, and fast way The most effective way of declaring objects How to magic methods in JavaScript Make your code readable and expressive There are numerous practices and heuristics to make a code more readable, expressive, and clean. We will cover this topic later on, but here we will talk about syntactic sugar. The term means an alternative syntax that makes the code more expressive and readable. In fact, we already had some of this in JavaScript from the very beginning. For instance, the increment/decrement and addition/subtraction assignment operators inherited from C. foo++ is syntactic sugar for foo = foo + 1, and foo += bar is a shorter form for foo = foo + bar. Besides, we have a few tricks that serve the same purpose. JavaScript applies logical expressions to so-called short-circuit evaluation. This means that an expression is read left to right, but as soon as the condition result is determined at an early stage, the expression tail is not evaluated. If we have true || false || false, the interpreter will know from the first test that the result is true regardless of other tests. So the false || false part is not evaluated, and this opens a way for creativity. Function argument default value When we need to specify default values for parameters we can do like that: function stub( foo ) { return foo || "Default value"; } console.log( stub( "My value" ) ); // My value console.log( stub() ); // Default value What is going on here? When foo is true (not undefined, NaN, null, false, 0, or ""), the result of the logical expression is foo otherwise the expression is evaluated until Default value and this is the final result. Starting with 6th edition of EcmaScript (specification of JavaScript language) we can use nicer syntax: function stub( foo = "Default value" ) { return foo; } Conditional invocation While composing our code we shorten it on conditions:" var age = 20; age >= 18 && console.log( "You are allowed to play this game" ); age >= 18 || console.log( "The game is restricted to 18 and over" ); In the preceding example, we used the AND (&&) operator to invoke console.log if the left-hand condition is Truthy. The OR (||) operator does the opposite, it calls console.log if the condition is Falsy. I think the most common case in practice is the shorthand condition where the function is called only when it is provided: /** * @param {Function} [cb] - callback */ function fn( cb ) { cb && cb(); }; The following is one more example on this: /** * @class AbstractFoo */ AbstractFoo = function(){ // call this.init if the subclass has init method this.init && this.init(); }; Syntactic sugar was introduced to its full extent to the JavaScript world only with the advance in CoffeeScript, a subset of the language that trans-compiles (compiles source-to-source) into JavaScript. Actually CoffeeScript, inspired by Ruby, Python, and Haskell, has unlocked arrow-functions, spreads, and other syntax to JavaScript developers. In 2011, Brendan Eich (the author of JavaScript) admitted that CoffeeScript influenced him in his work on EcmaScript Harmony, which was finalized this summer in ECMA-262 6th edition specification. From a marketing perspective, the specification writers agreed on using a new name convention that calls the 6th edition as EcmaScript 2015 and the 7th edition as EcmaScript 2016. Yet the community is used to abbreviations such as ES6 and ES7. To avoid confusion further in the book, we will refer to the specifications by these names. Now we can look at how this affects the new JavaScript. Arrow functions Traditional function expression may look like this: function( param1, param2 ){ /* function body */ } When declaring an expression using the arrow function (aka fat arrow function) syntax, we will have this in a less verbose form, as shown in the following: ( param1, param2 ) => { /* function body */ } In my opinion, we don't gain much with this. But if we need, let's say, an array method callback, the traditional form would be as follows: function( param1, param2 ){ return expression; } Now the equivalent arrow function becomes shorter, as shown here: ( param1, param2 ) => expression We may do filtering in an array this way: // filter all the array elements greater than 2 var res = [ 1, 2, 3, 4 ].filter(function( v ){ return v > 2; }) console.log( res ); // [3,4] Using an array function, we can do filtering in a cleaner form: var res = [ 1, 2, 3, 4 ].filter( v => v > 2 ); console.log( res ); // [3,4] Besides shorter function declaration syntax, the arrow functions bring the so called lexical this. Instead of creating its own context, it uses the context of the surrounding object as shown here: "use strict"; /** * @class View */ let View = function(){ let button = document.querySelector( "[data-bind="btn"]" ); /** * Handle button clicked event * @private */ this.onClick = function(){ console.log( "Button clicked" ); }; button.addEventListener( "click", () => { // we can safely refer surrounding object members this.onClick(); }, false ); } In the preceding example, we subscribed a handler function to a DOM event (click). Within the scope of the handler, we still have access to the view context (this), so we don't need to bind the handler to the outer scope or pass it as a variable through the closure: var that = this; button.addEventListener( "click", function(){ // cross-cutting concerns that.onClick(); }, false ); Method definitions As mentioned in the preceding section, arrow functions can be quite handy when declaring small inline callbacks, but always applying it for a shorter syntax is controversial. However, ES6 provides new alternative method definition syntax besides the arrow functions. The old-school method declaration may look as follows: var foo = { bar: function( param1, param2 ) { } } In ES6 we can get rid of the function keyword and the colon. So the preceding code can be put this way: let foo = { bar ( param1, param2 ) { } } The rest operator Another syntax structure that was borrowed from CoffeeScript came to JavaScript as the rest operator (albeit, the approach is called splats in CoffeeScript). When we had a few mandatory function parameters and an unknown number of rest parameters, we used to do something like this: "use strict"; var cb = function() { // all available parameters into an array var args = [].slice.call( arguments ), // the first array element to foo and shift foo = args.shift(), // the new first array element to bar and shift bar = args.shift(); console.log( foo, bar, args ); }; cb( "foo", "bar", 1, 2, 3 ); // foo bar [1, 2, 3] Now check out how expressive this code becomes in ES6: let cb = function( foo, bar, ...args ) { console.log( foo, bar, args ); } cb( "foo", "bar", 1, 2, 3 ); // foo bar [1, 2, 3] Function parameters aren't the only application of the rest operator. For example, we can use it in destructions as well, as follows: let [ bar, ...others ] = [ "bar", "foo", "baz", "qux" ]; console.log([ bar, others ]); // ["bar",["foo","baz","qux"]] The spread operator Similarly, we can spread array elements into arguments: let args = [ 2015, 6, 17 ], relDate = new Date( ...args ); console.log( relDate.toString() ); // Fri Jul 17 2015 00:00:00 GMT+0200 (CEST) Mastering multiline strings in JavaScript Multi-line strings aren't a good part of JavaScript. While they are easy to declare in other languages (for instance, NOWDOC), you cannot just keep single-quoted or double-quoted strings in multiple lines. This will lead to syntax error as every line in JavaScript is considered as a possible command. You can set backslashes to show your intention: var str = "Lorem ipsum dolor sit amet, n consectetur adipiscing elit. Nunc ornare, n diam ultricies vehicula aliquam, mauris n ipsum dapibus dolor, quis fringilla leo ligula non neque"; This kind of works. However, as soon as you miss a trailing space, you get a syntax error, which is not easy to spot. While most script agents support this syntax, it's, however, not a part of the EcmaScript specification. In the times of EcmaScript for XML (E4X), we could assign a pure XML to a string, which opened a way for declarations such as these: var str = <>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ornare </>.toString(); Nowadays E4X is deprecated, it's not supported anymore. Concatenation versus array join We can also use string concatenation. It may feel clumsy, but it's safe: var str = "Lorem ipsum dolor sit amet, n" + "consectetur adipiscing elit. Nunc ornare,n" + "diam ultricies vehicula aliquam, mauris n" + "ipsum dapibus dolor, quis fringilla leo ligula non neque"; You may be surprised, but concatenation is slower than array joining. So the following technique will work faster: var str = [ "Lorem ipsum dolor sit amet, n", "consectetur adipiscing elit. Nunc ornare,n", "diam ultricies vehicula aliquam, mauris n", "ipsum dapibus dolor, quis fringilla leo ligula non neque"].join( "" ); Template literal What about ES6? The latest EcmaScript specification introduces a new sort of string literal, template literal: var str = `Lorem ipsum dolor sit amet, n consectetur adipiscing elit. Nunc ornare, n diam ultricies vehicula aliquam, mauris n ipsum dapibus dolor, quis fringilla leo ligula non neque`; Now the syntax looks elegant. But there is more. Template literals really remind us of NOWDOC. You can refer any variable declared in the scope within the string: "use strict"; var title = "Some title", text = "Some text", str = `<div class="message"> <h2>${title}</h2> <article>${text}</article> </div>`; console.log( str ); The output is as follows: <div class="message"> <h2>Some title</h2> <article>Some text</article> </div> If you wonder when can you safely use this syntax, I have a good news for you—this feature is already supported by (almost) all the major script agents (http://kangax.github.io/compat-table/es6/). Multi-line strings via transpilers With the advance of ReactJS, Facebook's EcmaScript language extension named JSX (https://facebook.github.io/jsx/) is now really gaining momentum. Apparently influenced by previously mentioned E4X, they proposed a kind of string literal for XML-like content without any screening at all. This type supports template interpolation similar to ES6 templates: "use strict"; var Hello = React.createClass({ render: function() { return <div class="message"> <h2>{this.props.title}</h2> <article>{this.props.text}</article> </div>; } }); React.render(<Hello title="Some title" text="Some text" />, node); Another way to declare multiline strings is by using CommonJS Compiler (http://dsheiko.github.io/cjsc/). While resolving the 'require' dependencies, the compiler transforms any content that is not .js/.json content into a single-line string: foo.txt Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ornare, diam ultricies vehicula aliquam, mauris ipsum dapibus dolor, quis fringilla leo ligula non neque consumer.js var str = require( "./foo.txt" ); console.log( str ); Manipulating arrays in the ES5 way Some years ago when the support of ES5 features was poor (EcmaScript 5th edition was finalized in 2009), libraries such as Underscore and Lo-Dash got highly popular as they provided a comprehensive set of utilities to deal with arrays/collections. Today, many developers still use third-party libraries (including jQuery/Zepro) for methods such as map, filter, every, some, reduce, and indexOf, while these are available in the native form of JavaScript. It still depends on how you use such libraries, but it may likely happen that you don't need them anymore. Let's see what we have now in JavaScript. Array methods in ES5 Array.prototype.forEach is probably the most used method of the arrays. That is, it is the native implementation of _.each, or for example, of the $.each utilities. As parameters, forEach expects an iteratee callback function and optionally a context in which you want to execute the callback. It passes to the callback function an element value, an index, and the entire array. The same parameter syntax is used for most array manipulation methods. Note that jQuery's $.each has the inverted callback parameters order: "use strict"; var data = [ "bar", "foo", "baz", "qux" ]; data.forEach(function( val, inx ){ console.log( val, inx ); }); Array.prototype.map produces a new array by transforming the elements of a given array: "use strict"; var data = { bar: "bar bar", foo: "foo foo" }, // convert key-value array into url-encoded string urlEncStr = Object.keys( data ).map(function( key ){ return key + "=" + window.encodeURIComponent( data[ key ] ); }).join( "&" ); console.log( urlEncStr ); // bar=bar%20bar&foo=foo%20foo Array.prototype.filter returns an array, which consists of given array values that meet the callback's condition: "use strict"; var data = [ "bar", "foo", "", 0 ], // remove all falsy elements filtered = data.filter(function( item ){ return !!item; }); console.log( filtered ); // ["bar", "foo"] Array.prototype.reduce/Array.prototype.reduceRight retrieves the product of values in an array. The method expects a callback function and optionally the initial value as arguments. The callback function receive four parameters: the accumulative value, current one, index and original array. So we can, for an instance, increment the accumulative value by the current one (return acc += cur;) and, thus, we will get the sum of array values. Besides calculating with these methods, we can concatenate string values or arrays: "use strict"; var data = [[ 0, 1 ], [ 2, 3 ], [ 4, 5 ]], arr = data.reduce(function( prev, cur ) { return prev.concat( cur ); }), arrReverse = data.reduceRight(function( prev, cur ) { return prev.concat( cur ); }); console.log( arr ); // [0, 1, 2, 3, 4, 5] console.log( arrReverse ); // [4, 5, 2, 3, 0, 1] Array.prototype.some tests whether any (or some) values of a given array meet the callback condition: "use strict"; var bar = [ "bar", "baz", "qux" ], foo = [ "foo", "baz", "qux" ], /** * Check if a given context (this) contains the value * @param {*} val * @return {Boolean} */ compare = function( val ){ return this.indexOf( val ) !== -1; }; console.log( bar.some( compare, foo ) ); // true In this example, we checked whether any of the bar array values are available in the foo array. For testability, we need to pass a reference of the foo array into the callback. Here we inject it as context. If we need to pass more references, we would push them in a key-value object. As you probably noticed, we used in this example Array.prototype.indexOf. The method works the same as String.prototype.indexOf. This returns an index of the match found or -1. Array.prototype.every tests whether every value of a given array meets the callback condition: "use strict"; var bar = [ "bar", "baz" ], foo = [ "bar", "baz", "qux" ], /** * Check if a given context (this) contains the value * @param {*} val * @return {Boolean} */ compare = function( val ){ return this.indexOf( val ) !== -1; }; console.log( bar.every( compare, foo ) ); // true If you are still concerned about support for these methods in a legacy browser as old as IE6-7, you can simply shim them with https://github.com/es-shims/es5-shim. Array methods in ES6 In ES6, we get just a few new methods that look rather like shortcuts over the existing functionality. Array.prototype.fill populates an array with a given value, as follows: "use strict"; var data = Array( 5 ); console.log( data.fill( "bar" ) ); // ["bar", "bar", "bar", "bar", "bar"] Array.prototype.includes explicitly checks whether a given value exists in the array. Well, it is the same as arr.indexOf( val ) !== -1, as shown here: "use strict"; var data = [ "bar", "foo", "baz", "qux" ]; console.log( data.includes( "foo" ) ); Array.prototype.find filters out a single value matching the callback condition. Again, it's what we can get with Array.prototype.filter. The only difference is that the filter method returns either an array or a null value. In this case, this returns a single element array, as follows: "use strict"; var data = [ "bar", "fo", "baz", "qux" ], match = function( val ){ return val.length < 3; }; console.log( data.find( match ) ); // fo Traversing an object in an elegant, reliable, safe, and fast way It is a common case when we have a key-value object (let's say options) and need to iterate it. There is an academic way to do this, as shown in the following code: "use strict"; var options = { bar: "bar", foo: "foo" }, key; for( key in options ) { console.log( key, options[ key] ); } The preceding code outputs the following: bar bar foo foo Now let's imagine that any of the third-party libraries that you load in the document augments the built-in Object: Object.prototype.baz = "baz"; Now when we run our example code, we will get an extra undesired entry: bar bar foo foo baz baz The solution to this problem is well known, we have to test the keys with the Object.prototype.hasOwnProperty method: //… for( key in options ) { if ( options.hasOwnProperty( key ) ) { console.log( key, options[ key] ); } } Iterating the key-value object safely and fast Let's face the truth—the structure is clumsy and requires optimization (we have to perform the hasOwnProperty test on every given key). Luckily, JavaScript has the Object.keys method that retrieves all string-valued keys of all enumerable own (non-inherited) properties. This gives us the desired keys as an array that we can iterate, for instance, with Array.prototype.forEach: "use strict"; var options = { bar: "bar", foo: "foo" }; Object.keys( options ).forEach(function( key ){ console.log( key, options[ key] ); }); Besides the elegance, we get a better performance this way. In order to see how much we gain, you can run this online test in distinct browsers such as: http://codepen.io/dsheiko/pen/JdrqXa. Enumerating an array-like object Objects such as arguments and nodeList (node.querySelectorAll, document.forms) look like arrays, in fact they are not. Similar to arrays, they have the length property and can be iterated in the for loop. In the form of objects, they can be traversed in the same way that we previously examined. But they do not have any of the array manipulation methods (forEach, map, filter, some and so on). The thing is we can easily convert them into arrays as shown here: "use strict"; var nodes = document.querySelectorAll( "div" ), arr = Array.prototype.slice.call( nodes ); arr.forEach(function(i){ console.log(i); }); The preceding code can be even shorter: arr = [].slice.call( nodes ) It's a pretty convenient solution, but looks like a trick. In ES6, we can do the same conversion with a dedicated method: arr = Array.from( nodes ); The collections of ES6 ES6 introduces a new type of objects—iterable objects. These are the objects whose elements can be retrieved one at a time. They are quite the same as iterators in other languages. Beside arrays, JavaScript received two new iterable data structures, Set and Map. Set which are a collection of unique values: "use strict"; let foo = new Set(); foo.add( 1 ); foo.add( 1 ); foo.add( 2 ); console.log( Array.from( foo ) ); // [ 1, 2 ] let foo = new Set(), bar = function(){ return "bar"; }; foo.add( bar ); console.log( foo.has( bar ) ); // true The map is similar to a key-value object, but may have arbitrary values for the keys. And this makes a difference. Imagine that we need to write an element wrapper that provides jQuery-like events API. By using the on method, we can pass not only a handler callback function but also a context (this). We bind the given callback to the cb.bind( context ) context. This means addEventListener receives a function reference different from the callback. How do we unsubscribe the handler then? We can store the new reference in Map by a key composed from an event name and a callback function reference: "use strict"; /** * @class * @param {Node} el */ let El = function( el ){ this.el = el; this.map = new Map(); }; /** * Subscribe a handler on event * @param {String} event * @param {Function} cb * @param {Object} context */ El.prototype.on = function( event, cb, context ){ let handler = cb.bind( context || this ); this.map.set( [ event, cb ], handler ); this.el.addEventListener( event, handler, false ); }; /** * Unsubscribe a handler on event * @param {String} event * @param {Function} cb */ El.prototype.off = function( event, cb ){ let handler = cb.bind( context ), key = [ event, handler ]; if ( this.map.has( key ) ) { this.el.removeEventListener( event, this.map.get( key ) ); this.map.delete( key ); } }; Any iterable object has methods, keys, values, and entries, where the keys work the same as Object.keys and the others return array values and an array of key-value pairs respectively. Now let's see how we can traverse the iterable objects: "use strict"; let map = new Map() .set( "bar", "bar" ) .set( "foo", "foo" ), pair; for ( pair of map ) { console.log( pair ); } // OR let map = new Map([ [ "bar", "bar" ], [ "foo", "foo" ], ]); map.forEach(function( value, key ){ console.log( key, value ); }); Iterable objects have manipulation methods such as arrays. So we can use forEach. Besides, they can be iterated by for...in and for...of loops. The first one retrieves indexes and the second, the values. Summary This article gives practices and tricks on how to use the JavaScript core features for the maximum effect. This article also discusses the techniques to improve the expressiveness of the code, to master multi-line strings and templating, and to manipulate arrays and array-like objects. Further, we are introduced to the "magic methods" of JavaScript and gives a practical example of their use. JavaScript was born as a scripting language at the most inappropriate time—the time of browser wars. It was neglected and misunderstood for a decade and endured six editions. And look at it now! JavaScript has become a mainstream programming language. You can learn more about JavaScript with the help of the following books: https://www.packtpub.com/application-development/mastering-javascript-design-patterns https://www.packtpub.com/application-development/javascript-promises-essentials https://www.packtpub.com/application-development/learning-javascript-data-structures-and-algorithms Resources for Article: Further resources on this subject: Using JavaScript with HTML[article] Dart with JavaScript[article] Creating a basic JavaScript plugin[article]
Read more
  • 0
  • 0
  • 3047
article-image-working-sbs-services-user-part-1
Packt
23 Oct 2009
6 min read
Save for later

Working with SBS Services as a User: Part 1

Packt
23 Oct 2009
6 min read
E-mail, Calendar, and Contacts SBS 2008 includes Exchange 2007, which provides E-mail, Calendar, and Contact functionality. This is available through Outlook, over the Web via Outlook Web Access and on mobile devices. If the user makes a change to one, it will be replicated to Exchange and then to the other locations. How to access from the other locations will be covered later in this article. I'm going to presume that you understand how to send and read email and create and use contacts, but I will share some useful scenarios that many small businesses benefit from, but don't always understand are present in SBS 2008. Some of these will rely on Office 2007 with Outlook, while others can be seen via the web-based interface too. The scenarios are: Viewing your calendar and other people's calendars Scheduling a meeting for multiple people and ensuring their diaries are all free for the time period Telling people when you are going to be away or unavailable Finding emails that have been filed Recovering emails that have been deleted and removed from the deleted items folder All of the actions in this section are carried out on a user's computer, logged in as that user. Only where SBS 2008 is explicitly mentioned, is there an action that is carried out on the server. Outlook 2003 and 2007 connection configuration To configure Microsoft Outlook 2007, you should simply have to open Outlook as it should auto-configure itself. Outlook 2003 will require configuring, but I'm only going cover the important sections here. For full instructions, click on the link How do I use Outlook Anywhere, on the Remote Web Workplace main screen. The links on Remote Web Workplace point to addresses that begin with https://sites/..., which is not accessible from outside the SBS 2008 network. This should be changed to https://remote.yourdomain.co.uk/... as described later in this article. If this has not been done and a user needs access to the information, then they can edit the address in their browser replacing the first part of the URL as described above. If you need to manually configure Outlook, you will need to select the server as an Exchange server. The name of the Microsoft Exchange Server is the name of your SBS 2008 server. In the following screenshot, the name of my SBS 2008 server is davidoverserver and this is entered into the Microsoft Exchange Server section, along with the User Name of the user I am logged in as on their computer. You can either click on Next to finish the settings, or if this is a laptop or a machine that may access SBS 2008 from a remote location, click on More Settings. Click on the Connection tab and then put a check mark in the Connect to my Exchange mailbox using HTTP check box. Finally, click the button Exchange Proxy Settings. Once the proxy settings are open, you will need to type in the remote access URL for your server and also check the Mutually authenticate the session when connecting with SSL, and then enter the name of your remote access server, preceded by msstd:. Clicking on OK will enable you to finish the configuration. Once these changes have been enabled, Outlook will connect to the network without any further action—provided you have an Internet connection, and should work offline until it gets an Internet connection. Calendar management SBS 2008 provides each user a calendar that they can use to manage their diary and which they can choose to share with colleagues if they desire. The level of details shared can be from very basic free and busy time slots through to enabling someone else to have the ability to see and change the diary. This availability of information does concern some users, which is why they can also mark any appointment as private and no details will be shared with others, even if the calendar has been fully shared. Outlook on the desktop enables access to both your and other's calendars, while Outlook and Windows Mobile devices offer much less, if any, access to other people's calendars. I will only describe each task from Outlook in this section, and will provide more information on using Outlook Web Access later in this article. Viewing Calendars Start Outlook from the Start menu. Once Outlook has loaded, click on the Calendar button or go to the Go menu and select Calendar from the menu. You will see your calendar displayed, normally in the Day format with today showing. In the example below, you can see the padlock for the private appointment that others can't see, two normal appointments, and the tentative appointment that is not confirmed at 17:00. To open another person's calendar, click the Open a Shared Calendar link on the lefthand side and then type in the name of the person whose calendar you want to see. If you have permission to view their calendar, you will see both calendars side by side as follows: If you do not have permission and you are running Outlook 2007, you will be prompted to send an email requesting permission. The email will look like this: If the person receiving this email has Outlook 2007, they simply click on Accept to enable you to view the calendar. If you or they have an earlier version of Outlook, then the person whose calendar you want to view will need to carry this task out by hand. To do this, get that individual to open Outlook and then their Calendar and right-click on Calendar under My Calendars and then select Properties from the menu. When the properties appear, go to the Permissions tab and either add the user and assign specific permission, or to make life easier, simply set the default access to reviewer. You can now view both your and other's calendars to identify opportunities to meet. You can open more than one other person's calendar, but things can get confusing with so many open. With Office 2007, you can overlay the calendars by clicking the arrow next to someone's name. For all versions of Outlook, you close a calendar by removing the check mark next to their name in the lefthand navigation pane.
Read more
  • 0
  • 0
  • 3045

article-image-web-api-and-client-integration
Packt
10 Oct 2014
9 min read
Save for later

Web API and Client Integration

Packt
10 Oct 2014
9 min read
In this article written by Geoff Webber-Cross, the author of Learning Microsoft Azure, we'll create an on-premise production management client Windows application allowing manufacturing staff to view and update order and batch data and a web service to access data in the production SQL database and send order updates to the Service Bus topic. (For more resources related to this topic, see here.) The site's main feature is an ASP.NET Web API 2 HTTP service that allows the clients to read order and batch data. The site will also host a SignalR (http://signalr.net/) hub that allows the client to update order and batch statuses and have the changes broadcast to all the on-premise clients to keep them synchronized in real time. Both the Web API and SignalR hubs will use the Azure Active Directory authentication. We'll cover the following topic in this article: Building a client application Building a client application For the client application, we'll create a WPF client application to display batches and orders and allow us to change their state. We'll use MVVM Light again, like we did for the message simulator we created in the sales solution, to help us implement a neat MVVM pattern. We'll create a number of data services to get data from the API using Azure AD authentication. Preparing the WPF project We'll create a WPF application and install NuGet packages for MVVM Light, JSON.NET, and Azure AD authentication in the following procedure (for the Express version of Visual Studio, you'll need Visual Studio Express for desktops): Add a WPF project to the solution called ManagementApplication. In the NuGet Package Manager Console, enter the following command to install MVVM Light: install-package mvvmlight Now, enter the following command to install the Microsoft.IdentityModel.Clients.ActiveDirectory package: install-package Microsoft.IdentityModel.Clients.ActiveDirectory Now, enter the following command to install JSON.NET: install-package newtonsoft.json Enter the following command to install the SignalR client package (note that this is different from the server package): Install-package Microsoft.AspNet.SignalR.Client Add a project reference to ProductionModel by right-clicking on the References folder and selecting Add Reference, check ProductionModel by navigating to the Solution | Projects tab, and click on OK. Add a project reference to System.Configuraton and System.Net.Http by right-clicking on the References folder and selecting Add Reference, check System.Config and System.Net.Http navigating to the Assemblies | Framework tab, and click on OK. In the project's Settings.settings file, add a string setting called Token to store the user's auth token. Add the following appSettings block to App.config; I've put comments to help you understand (and remember) what they stand for and added commented-out settings for the Azure API: <appSettings> <!-- AD Tenant --> <add key="ida:Tenant" value="azurebakery.onmicrosoft.com" />    <!-- The target api AD application APP ID (get it from    config tab in portal) --> <!-- Local --> <add key="ida:Audience"    value="https://azurebakery.onmicrosoft.com/ManagementWebApi" /> <!-- Azure --> <!-- <add key="ida:Audience"    value="https://azurebakery.onmicrosoft.com/      WebApp-azurebakeryproduction.azurewebsites.net" /> -->    <!-- The client id of THIS application (get it from    config tab in portal) --> <add key="ida:ClientID" value=    "1a1867d4-9972-45bb-a9b8-486f03ad77e9" />    <!-- Callback URI for OAuth workflow --> <add key="ida:CallbackUri"    value="https://azurebakery.com" />    <!-- The URI of the Web API --> <!-- Local --> <add key="serviceUri" value="https://localhost:44303/" /> <!-- Azure --> <!-- <add key="serviceUri" value="https://azurebakeryproduction.azurewebsites.net/" /> --> </appSettings> Add the MVVM Light ViewModelLocator to Application.Resources in App.xaml: <Application.Resources>    <vm:ViewModelLocator x_Key="Locator"      d_IsDataSource="True"                      DataContext="{Binding Source={StaticResource          Locator}, Path=Main}"        Title="Production Management Application"          Height="350" Width="525"> Creating an authentication base class Since the Web API and SignalR hubs use Azure AD authentication, we'll create services to interact with both and create a common base class to ensure that all requests are authenticated. This class uses the AuthenticationContext.AquireToken method to launch a built-in login dialog that handles the OAuth2 workflow and returns an authentication token on successful login: using Microsoft.IdentityModel.Clients.ActiveDirectory; using System; using System.Configuration; using System.Diagnostics; using System.Net;   namespace AzureBakery.Production.ManagementApplication.Services {    public abstract class AzureAdAuthBase    {        protected AuthenticationResult Token = null;          protected readonly string ServiceUri = null;          protected AzureAdAuthBase()        {            this.ServiceUri =              ConfigurationManager.AppSettings["serviceUri"]; #if DEBUG            // This will accept temp SSL certificates            ServicePointManager.ServerCertificateValidationCallback += (se, cert, chain, sslerror) => true; #endif        }          protected bool Login()        {            // Our AD Tenant domain name            var tenantId =              ConfigurationManager.AppSettings["ida:Tenant"];              // Web API resource ID (The resource we want to use)            var resourceId =              ConfigurationManager.AppSettings["ida:Audience"];              // Client App CLIENT ID (The ID of the AD app for this            client application)            var clientId =              ConfigurationManager.AppSettings["ida:ClientID"];              // Callback URI            var callback = new              Uri(ConfigurationManager.AppSettings["ida:CallbackUri"]);              var authContext = new              AuthenticationContext(string.Format("https://login.windows.net/{0}", tenantId));              if(this.Token == null)            {                // See if we have a cached token               var token = Properties.Settings.Default.Token;                if (!string.IsNullOrWhiteSpace(token))                    this.Token = AuthenticationResult.Deserialize(token);            }                       if (this.Token == null)             {                try                {                    // Acquire fresh token - this will get user to                    login                                  this.Token =                      authContext.AcquireToken(resourceId,                         clientId, callback);                }                catch(Exception ex)                {                    Debug.WriteLine(ex.ToString());                      return false;                }            }            else if(this.Token.ExpiresOn < DateTime.UtcNow)            {                // Refresh existing token this will not require                login                this.Token =                  authContext.AcquireTokenByRefreshToken(this.Token.RefreshToken,                   clientId);            }                      if (this.Token != null && this.Token.ExpiresOn >              DateTime.UtcNow)            {                // Store token                Properties.Settings.Default.Token =                  this.Token.Serialize(); // This should be                    encrypted                Properties.Settings.Default.Save();                  return true;            }              // Clear token            this.Token = null;              Properties.Settings.Default.Token = null;            Properties.Settings.Default.Save();              return false;        }    } } The token is stored in user settings and refreshed if necessary, so the users don't have to log in to the application every time they use it. The Login method can be called by derived service classes every time a service is called to check whether the user is logged in and whether there is a valid token to use. Creating a data service We'll create a DataService class that derives from the AzureAdAuthBase class we just created and gets data from the Web API service using AD authentication. First, we'll create a generic helper method that calls an API GET action using the HttpClient class with the authentication token added to the Authorization header, and deserializes the returned JSON object into a .NET-typed object T: private async Task<T> GetData<T>(string action) {    if (!base.Login())        return default(T);      // Call Web API    var authHeader = this.Token.CreateAuthorizationHeader();    var client = new HttpClient();    var uri = string.Format("{0}{1}", this.ServiceUri,      string.Format("api/{0}", action));    var request = new HttpRequestMessage(HttpMethod.Get, uri);    request.Headers.TryAddWithoutValidation("Authorization",      authHeader);      // Get response    var response = await client.SendAsync(request);    var responseString = await response.Content.ReadAsStringAsync();      // Deserialize JSON    var data = await Task.Factory.StartNew(() =>      JsonConvert.DeserializeObject<T>(responseString));      return data; } Once we have this, we can quickly create methods for getting order and batch data like this:   public async Task<IEnumerable<Order>> GetOrders() {    return await this.GetData<IEnumerable<Order>>("orders"); }   public async Task<IEnumerable<Batch>> GetBatches() {    return await this.GetData<IEnumerable<Batch>>("batches"); } This service implements an IDataService interface and is registered in the ViewModelLocator class, ready to be injected into our view models like this: SimpleIoc.Default.Register<IDataService, DataService>(); Creating a SignalR service We'll create another service derived from the AzureAdAuthBase class, which is called ManagementService, and which sends updated orders to the SignalR hub and receives updates from the hub originating from other clients to keep the UI updated in real time. First, we'll create a Register method, which creates a hub proxy using our authorization token from the base class, registers for updates from the hub, and starts the connection: private IHubProxy _proxy = null;   public event EventHandler<Order> OrderUpdated; public event EventHandler<Batch> BatchUpdated;   public ManagementService() {   }   public async Task Register() {    // Login using AD OAuth    if (!this.Login())        return;      // Get header from auth token    var authHeader = this.Token.CreateAuthorizationHeader();      // Create hub proxy and add auth token    var cnString = string.Format("{0}signalr", base.ServiceUri);    var hubConnection = new HubConnection(cnString, useDefaultUrl:      false);    this._proxy = hubConnection.CreateHubProxy("managementHub");    hubConnection.Headers.Add("Authorization", authHeader);      // Register for order updates    this._proxy.On<Order>("updateOrder", order =>    {        this.OnOrderUpdated(order);    });        // Register for batch updates    this._proxy.On<Batch>("updateBatch", batch =>    {        this.OnBatchUpdated(batch);    });        // Start hub connection    await hubConnection.Start(); } The OnOrderUpdated and OnBatchUpdated methods call events to notify about updates. Now, add two methods that call the hub methods we created in the website using the IHubProxy.Invoke<T> method: public async Task<bool> UpdateOrder(Order order) {    // Invoke updateOrder method on hub    await this._proxy.Invoke<Order>("updateOrder",      order).ContinueWith(task =>    {        return !task.IsFaulted;    });      return false; }   public async Task<bool> UpdateBatch(Batch batch) {    // Invoke updateBatch method on hub    await this._proxy.Invoke<Batch>("updateBatch",      batch).ContinueWith(task =>    {        return !task.IsFaulted;    });      return false; } This service implements an IManagementService interface and is registered in the ViewModelLocator class, ready to be injected into our view models like this: SimpleIoc.Default.Register<IManagementService, ManagementService>(); Testing the application To test the application locally, we need to start the Web API project and the WPF client application at the same time. So, under the Startup Project section in the Solution Properties dialog, check Multiple startup projects, select the two applications, and click on OK: Once running, we can easily debug both applications simultaneously. To test the application with the service running in the cloud, we need to deploy the service to the cloud, and then change the settings in the client app.config file (remember we put the local and Azure settings in the config with the Azure settings commented-out, so swap them around). To debug the client against the Azure service, make sure that only the client application is running (select Single startup project from the Solution Properties dialog). Summary We learned how to use a Web API to enable the production management Windows client application to access data from our production database and a SignalR hub to handle order and batch changes, keeping all clients updated and messaging the Service Bus topic. Resources for Article: Further resources on this subject: Using the Windows Azure Platform PowerShell Cmdlets [Article] Windows Azure Mobile Services - Implementing Push Notifications using [Article] Using Azure BizTalk Features [Article]
Read more
  • 0
  • 0
  • 3044
Modal Close icon
Modal Close icon