Chapter 11

Working with Cloud Development Services

WHAT YOU WILL LEARN IN THIS CHAPTER:

  • Understanding the different kinds of cloud development services
  • Using the FeedHenry app development platform
  • Using the Appcelerator app development platform
  • Using the appMobi app development platform

In this book, you have learned how to build a cloud-based mobile app from the ground up. You have done everything yourself, including setting up your own Amazon server. You’ve used the Amazon cloud, but you’ve still had to do a lot of system administration work yourself. You will often need this level of control, and the knowledge you’ve gained in this book will be very useful when you need to meet client requirements in a flexible way.

Sometimes, you will not need quite so much control, and it may be more cost-effective to let someone else worry about server configuration. In such cases, you can use prebuilt services in the cloud and focus on building your mobile app. This chapter looks at three commercial vendors that can help you build apps very quickly, by abstracting away many of the details.

It is useful to have a conceptual framework in order to help make a decision about what cloud vendor to use. There are three main types of cloud services:

  • Infrastructure-as-a-service — You get virtual infrastructure software, such as operating systems, databases, and file storage. Amazon and Rackspace are good examples.
  • Platform-as-a-service — You get a prebuilt execution environment for your code, and the service looks after all the infrastructure elements. The Heroku cloud environment for Ruby web apps is the archetypal example here.
  • Software-as-a-service — You do not need to write any code, you just use an online service for a particular purpose, such as email. Gmail and Hotmail are perfect examples.

This book has focused on the first type: infrastructure-as-a-service. Amazon remains the leading company in this area, and familiarity with Amazon’s systems is essential knowledge for a web and mobile developer.

The software-as-a-service cloud services are not particularly useful to you as a developer for building apps. While you may need to integrate with cloud services of this kind — for example, social media sites — in general, your interaction with these kinds of services will be more about using their APIs for integration. You’ve already learned how to use the social media sites for easy user login. In the next two chapters, you’ll extend that knowledge to include the use of social media APIs.

So what you really need is the platform-as-a-service offerings. This chapter takes a look at the three leading companies in the JavaScript-based mobile app development space. Other companies provide mobile app development services, such as Rhomobile (which uses Ruby), but they do not support JavaScript as a development language.

What you are looking for from a service like this is a way to reduce the amount of work you have to do to build a production-quality app that integrates with your own and third-party cloud services. You should not need to install any server software. The service should be able to build app binaries that you can submit directly to the app stores. And the service should provide you with pre-built modules for common requirements such as e-commerce, push notifications, and analytics. The service should also provide a place to run your server-side business logic and store your app data in the cloud. Such an ideal service does not yet exist. But if you understand what the three leading services can provide, you will be able to understand the necessary trade-offs between effort, features, and price.

GETTING TO KNOW THE MOBILE APP DEVELOPMENT PLATFORMS

This book has shown you how to develop JavaScript-based mobile apps by using open source tools. But this is not the only option for building mobile apps using JavaScript. A number of commercial offerings have emerged that promise to make your development life easier. It is, of course, entirely possible to build an app using only PhoneGap and open source server software. However, doing this may not be advisable if you need to meet tight deadlines and provide certain levels of postdeployment support. Especially when you are dealing with large clients, or when you need special capabilities such as augmented reality, it is worth considering a commercial development platform.

This chapter takes a look at the commercial mobile and cloud platforms that allow you to build an app using JavaScript. There are other excellent platforms based on other languages, but we don’t cover them here because the focus is on using the techniques and skills you have developed in reading this book.

You’ll learn about three platforms: FeedHenry, Appcelerator, and appMobi. As a preview, here is a feature comparison table:

image

USING THE FEEDHENRY PLATFORM

FeedHenry (www.feedhenry.com) was one of the first companies to offer a production-quality cross-platform app development service using HTML5 as the core technology. Founded in 2007, FeedHenry started with a web app framework and adapted it for mobile uses. In addition to this HTML5 strategy on the client, FeedHenry from the start has offered a cloud-hosting platform that enables you to develop server-side JavaScript business logic. Initially this system was delivered using the Java-based Rhino engine from Mozilla, but FeedHenry now uses Node, which means you can directly apply everything you have learned in this book.

image

NOTE Disclaimer: I was the chief technology officer of FeedHenry from 2007 until 2010.

FeedHenry allows you to take advantage of the techniques you have learned in this book to build a mobile app using JavaScript, CSS, and HTML. Whereas Amazon is an infrastructure-as-a-service cloud offering, FeedHenry is a platform-as-a-service offering. This means that with FeedHenry, you do not need to concern yourself with the management and maintenance of your servers. Instead, the FeedHenry system looks after scaling of your apps when load increases and also ensures that your apps remain running at all times. The FeedHenry system is designed so that you only have to focus on the development of your app and don’t need to worry about system administration. This means you can build and deploy apps much faster.

Of course, you have to operate within the constraints of the system, and you’ll need to determine whether this strategy is appropriate for your needs. The approach is particularly powerful for developing enterprise mobile apps leveraging existing web service end points, as the FeedHenry server side can act as a security and performance management buffer between these end points and the mobile apps, through the use of intelligent caching.

Figure 11-1 shows the main app management dashboard of the FeedHenry service.

FeedHenry Technology

The core concept of the FeedHenry service is that you should be able to use JavaScript on both the client and the server. FeedHenry also makes sure that you can use the same API on both the client and server and that this API deliberately has a small footprint and is thus easy to learn and use.

On the client side, you can continue to use your favorite JavaScript libraries, such as jQuery and jQuery Mobile, or other libraries that you may prefer. In addition, all the examples in this book will work with FeedHenry, with only minor modifications. The FeedHenry client-side API provides an abstraction for common device and cloud functions. It is similar to the PhoneGap API, and it allows you to perform most of the device interactions you need, such as camera access.

On the server side, you can use your experience with Node to build out your business logic. FeedHenry allows you to deploy your own Node modules, using a sandbox system. You have access to a virtualized machine environment, and you do not have significant limitations on the types of modules you can use. Again, this is a design feature of the system. Because this cloud hosting feature of the FeedHenry service is based on Node, it takes advantage of an event-based architecture, which means you can build robust and high-performance services for your mobile apps. FeedHenry also provides access to a hosted MongoDB database, and you can also access external database services, such as MongoHQ.com or Amazon RDS. The FeedHenry-hosted MongoDB database gives you a high-scale, low-latency data store and is fully integrated into the API. In case you are working in an enterprise software environment, FeedHenry also offers a multi-tenancy architecture that lets you specify multiple kinds of user and access permissions.

If you decide to use the FeedHenry system, you need to consider a number of factors. It is a proprietary system, and when you take full advantage of its features, you are to a certain extent locked in. This is particularly true if you use the FeedHenry API, the cloud database, or the multi-tenancy features. The system is deliberately designed to leverage HTML5. This is great for standards compliance, but it leaves you on your own to build the entire client-side code architecture yourself. FeedHenry provides sample applications that you can clone to get started, but you must essentially start from a blank slate.

FeedHenry is oriented toward enterprise app development. This can be useful for you if you’re an independent developer or small development house that has a large company as a client. It means you can rely on the FeedHenry enterprise features such as service-level agreements and 24-hour monitoring and support. If you are looking to build your own apps, you should first consider whether you really need the extensive cloud hosting features, as you will have to pay for them.

The advantages of using the FeedHenry system are that you can reuse your knowledge of HTML5, JavaScript, and CSS right away. You do not even need to learn the FeedHenry API to get started. FeedHenry has an easy-to-use build system hosted in the cloud that does all the hard work of building apps for you. Unlike Appcelerator, discussed next, FeedHenry does not require you to install separate software development kits (SDKs) from Apple or Google. Instead, you can press a button and get an app binary right away, ready for submission to the iPhone App Store and Android Marketplace.

The FeedHenry Development Environment

The primary development environment for FeedHenry is an online IDE. You can build your apps entirely in the cloud, using your web browser, without downloading or installing anything. The IDE has a main dashboard that lists all your apps, an account management area, and a documentation area. Finding your way around is quite easy.

The development area gives you an in-browser code editor, with syntax highlighting for HTML, JavaScript, and CSS. The editor struggles a little bit with very large files, but for the most part is very usable. The editor follows the traditional IDE layout, with a folder-and-file hierarchy on the left and the main code body on the right. In addition, you can see a preview of your app on the left. The FeedHenry system uses your own browser to generate a preview of your app that is fully interactive. This enables a very rapid development cycle because you can see your changes immediately. If the preview is too large, then it automatically pops out of the browser window.

With FeedHenry, you can configure the various build options for your app. In order to create app binaries that you can submit to the app stores, you need to upload your app-signing certificates. FeedHenry stores them securely for you and uses them to build your app in its cloud build system. You are thus freed from the requirement to have a local build environment. In particular, FeedHenry allows you to build iPhone apps without owning a Mac.

Because FeedHenry also offers a cloud hosting platform, it has a debugging section that allows you to review any log entries that your server-side business logic has generated. As with the client-side app development, the aim here is for you to never have to leave the browser IDE. Figure 11-2 shows the code editor area of the IDE.

FeedHenry is not limited to the online IDE. You can also build your apps locally, using your own development tools. FeedHenry offers a downloadable integration application that lets you manage your apps from your desktop. The integration application is also available as an Eclipse plug-in. Finally, FeedHenry offers GitHub integration (see http://github.com), enabling you to pull your app code directly from GitHub.

Deciding to Use FeedHenry

FeedHenry’s pricing is structured for enterprise customers. FeedHenry also provides many of the ancillary services that large companies need, such as support and service guarantees.

If you need maximum flexibility, FeedHenry is also a good option. You have the same level of flexibility as if you are using PhoneGap. There are no restrictions on the client-side libraries you can include, and you can use most Node modules. You can export the full source code of your app, and you can customize it in any way you like.

Unlike some of the other services described in this chapter, FeedHenry does not provide many additional components, such as data synchronization or alerting. However, because you have a full server-side cloud hosting platform at your disposal, you can easily integrate with any third-party service that offers a web service interface. Because you can do this from either the client or the server, your integration work is very easy. Your server-side code can even expose its own mini web service API, which is very difficult to do with services that only allow you to execute code on the client.

FeedHenry offers its own analytics solution. It covers all the bases that you would expect, showing you app usage levels, active users, and device details. You can also track the interaction pathways through your app, and this helps you understand which aspects of your app interface are user friendly and which are not. There is also an option to use the Flurry analytics service.

FeedHenry offers extensive device coverage. This book focuses on the two main platforms, iPhone and Android, but FeedHenry also allows you to build apps for Windows Mobile, BlackBerry, and Nokia Web Runtime. There are some challenges supporting platforms beyond iPhone and Android in terms of HTML5 compliance and the requirement to write some platform-specific code. FeedHenry makes this much easier by allowing you to break your app into constituent files that can be customized on a per-platform basis.

USING THE APPCELERATOR PLATFORM

Appcelerator (www.appcelerator.com) was founded in 2006, and with over 1 million developers, is one of the most popular services for cross-platform mobile app development. You develop apps using JavaScript and a proprietary API. This API has the same purpose as the PhoneGap API, but it is considerably deeper and more extensive. The big idea that Appcelerator brings to the table is that you can build your app using only JavaScript — no HTML or CSS is required! Developing with Appcelerator is thus more similar to traditional user interface development, in that you use API calls to build your user interface programmatically. You specify the entire user interface using only JavaScript. If you intend to use the examples in this book on the Appcelerator platform, you will need to do two things: convert the API calls to use the Appcelerator API and replace the HTML/CSS code with user interface–building JavaScript code.

One of the other great things about Appcelerator is that it offers a fully featured IDE similar to Eclipse or Xcode, known as Appcelerator Studio. From within this IDE you can build, test, and deploy your mobile apps.

Appcelerator primarily focuses on mobile app development but also offers a number of vertical cloud modules that provide integration with social media services such as Twitter and Facebook, as well as e-commerce services such as PayPal. It gives you a ready-made software toolkit that lets you provide many commonly requested features in your apps.

When you create an account on the Appcelerator service, you are given access to an online account administration area where you can list your apps, review their analytics charts, and buy access to some of the commercial cloud modules. Figure 11-3 shows the main dashboard.

Appcelerator Technology

The key idea behind Appcelerator is that its JavaScript API calls native Objective-C or Java code for iPhone and Android, respectively. Your Appcelerator app executes your JavaScript code on the mobile device as normal, but the Appcelerator API uses the native device API instead of manipulating an HTML document. The advantage here is that your user interface is built using native interface controls rather than being constructed from HTML and CSS. This gives you a significant performance improvement. Of course, you are making the choice to develop your app using a proprietary API rather than the HTML5 web standard.

The Appcelerator API is extensive and covers everything covered by the PhoneGap project. In the last few chapters, you used the PhoneGap project to build the LifeStream app as a native app. You will find that the Appcelerator API, while different, has a similar feel and set of concepts to PhoneGap. In addition, the Appcelerator API provides other functions, such as Facebook integration, mapping support, and finer-grained access to device capabilities. As a strategic move to gain developer adoption, Appcelerator has made its API open source. You are not limited to the functions Appcelerator provides. You can also use Objective-C or Java to write your own extensions in much the same way as you write plug-ins with PhoneGap.

Unlike FeedHenry, Appcelerator does not provide a cloud hosting service and does not enable you to run your server-side app code in its own cloud. Instead, you have to use a third-party service to do this. The Appcelerator Studio IDE has good integrated support for a number of the major cloud app hosting services. The only problem is that you will have to write your server-side code in Ruby or PHP, rather than JavaScript. As Node app hosting services go mainstream, this should become less of an issue.

Appcelerator provides better performance than embedded HTML due to the fact that its operation is more like that of a native app. The company has also made it really easy to develop apps based on common use cases, such as social media integration or data synchronization, by offering vertical modules inside the API that take care of these functions. It is thus very easy to get started building apps. The excellent IDE also makes development very easy and fluid. The company seems to have considerable momentum behind it and regularly releases updates with expanded features.

Appcelerator does have some disadvantages. There is a long-term industry trend toward HTML5. While you can use HTML5 with Appcelerator by embedding a WebView control, doing so negates almost all the advantages of the platform. When you use Appcelerator, you rely on a proprietary API. This API is comprehensive and well designed, but you must nonetheless place a bet on the success of the Appcelerator company rather than the Appcelerator technology. Although the development environment is very easy to use, it has a slow development cycle. In order to test your app, you must build it using the iPhone or Android SDK, and you have to install this alongside the Appcelerator IDE. This introduces an inevitable delay in your code–test–debug work cycle. The lack of support for general-purpose server-side code hosted in the cloud means that you must rely on yet another third party to fully deliver your app. Remember that most apps are not stand-alone but require some level of server-side business logic. Finally, of the three mobile app development platforms covered in this chapter, Appcelerator is the only one that requires you to extensively modify your code from the examples in this book.

The Appcelerator Development Environment

The Appcelerator IDE, called Titanium Studio, is similar to Eclipse. The IDE follows the standard convention of having a tree-based list of your files on the left, the main editor page in the middle, and a console with output at the bottom. You can launch your apps directly by clicking the Run button. You then choose whether to run an Android or iPhone app. You can run an app using an emulator or install it on a device. You can even build release versions and deploy your apps directly to the app stores. This is all very seamless and a really frictionless experience. The development environment offers integration with third-party cloud services such as Heroku, which makes life slightly easier when there is a cloud-hosted server-side component to your app, even if you have to write the business logic in Ruby! Figure 11-4 shows the IDE layout.

If you develop apps using Appcelerator, you have to commit yourself to learning the Appcelerator API. This investment of your time makes sense when you can also make use of the additional services that Appcelerator provides. The basic package from Appcelerator is free. However, you have to pay to use the more advanced vertical cloud modules, such as e-commerce integration. When these features are things that you need to build and deploy quickly for a client, using Appcelerator can really help.

Deciding to Use Appcelerator

Appcelerator uses a feature level–based pricing model that is common to many online services. The prices range from free to a few hundred dollars per month. As with FeedHenry, there is also an enterprise pricing structure, which includes professional services. The differences between the options are laid out in an easy-to-understand table at www.appcelerator.com/products/plans-pricing. The price differences are mostly driven by the different types of vertical modules and ancillary services.

Using Appcelerator is not as immediately flexible as using an approach based directly on HTML5. To customize the Appcelerator solution, you need to be able to code in Objective-C or Java. It is not enough to have HTML, CSS, and JavaScript knowledge. On the other hand, because Appcelerator uses native user interface controls and ultimately has access to the native capabilities of the device, your app can have a far more native feel than HTML5-based apps.

Appcelerator provides a basic HTTP client as part of the API that you can use to integrate with third-party web services. The calls to a web service must take place from the device, unlike with FeedHenry, where calls can happen both from the device and from the FeedHenry cloud. Appcelerator does not provide any additional support for third-party integration, and you may find that you need to do more work on the server yourself. The Appcelerator API does provide support for the JSON and XML data formats, which makes web service integration easier.

Appcelerator provides an in-house analytics solution that lets you track how your users are interacting with your app. As well as the standard mobile app analytics, such as device type, session duration, and usage levels, you can also track custom events. The analytics element of the Appcelerator service is quite comprehensive, and while not real-time, is certainly competitive with focused offerings such as Flurry.

In terms of device coverage, Appcelerator focuses on iPhone and Android. This means you cannot as yet build applications of the same quality for other platforms, such as Windows Mobile or BlackBerry. You have to carefully consider the user base for your app as you determine whether Appcelerator is the right app platform for you. If you are an independent developer building a game or utility app, and primarily targeting the Apple App Store and Android Marketplace, then Appcelerator is certainly suitable. If you work for a large company and need to build an app that offers access to your services from a wide range of devices, then Appcelerator may be only part of your solution, and you may need to consider other options for supporting less popular platforms.

USING THE APPMOBI PLATFORM

appMobi (www.appmobi.com) grew out of the efforts of a mobile consulting company to streamline its cross-platform mobile app development efforts. Founded in 2006, appMobi is the end result of a large amount of work developing high-end mobile media applications using HTML5. As a result, the appMobi system is also quite suitable for game development, and the company promotes game development using JavaScript game engines such as ImpactJS and LimeJS. The underlying approach is the same as FeedHenry, using HTML5 to build the user interface, and it provides a JavaScript API for accessing device capabilities. Unlike FeedHenry, but like Appcelerator, appMobi opts for vertical cloud components rather than a general-purpose cloud hosting solution for your server-side business logic. Unlike both of the other services, appMobi does not offer an IDE, as such, but rather has an in-browser app development kit that includes a full-featured test and emulation environment.

As with FeedHenry, the appMobi service builds binary versions of your apps on its servers. This frees you from the requirement to install the iPhone and Android SDKs, which is something that Appcelerator does require. As with the two other platforms, appMobi provides an online account management interface, where you can control your apps and services. Figure 11-5 shows the main dashboard.

appMobi Technology

In terms of API complexity, appMobi is more complex than the small-footprint FeedHenry, but it is less complex than the Appcelerator kitchen-sink strategy. The API is quite similar to the PhoneGap API, so you should not have too much trouble finding your way around. appMobi takes the more common cross-platform approach of using HTML, CSS, and JavaScript to building apps. This means that, as with FeedHenry, you can reuse most of the code examples from this book.

Like Appcelerator, appMobi offers a suite of cloud services, such as e-commerce integration, push notifications, and analytics. It also provides an interesting service that can auto-update your app by downloading new versions of the static assets. While this is probably not entirely compatible with the Apple developer agreement, which prohibits apps from making drastic post-installation changes, it is certainly a great feature for your Android apps.

The appMobi API contains a fantastic augmented-reality feature. It allows you to show a live feed from the device camera and overlay your own interface elements. This is quite unique in the world of HTML5 apps. If you need an augmented-reality feature, than appMobi is definitely the way to go.

The core benefit of the appMobi approach is that with it, you are building on a standardized technology: HTML5. The appMobi API is quite comprehensive and offers good coverage of device capabilities, such as camera and file system access. Your development code–test–debug work cycle is streamlined because you can test directly in the browser. The appMobi solution has integrated design and a very consistent feel. It gets out of your way and allows you to concentrate on building apps.

The downside to appMobi, as with Appcelerator, is that you must find your own cloud hosting solution for your server-side business logic. While appMobi does provide a number of vertical cloud modules, you still need to use third-party services to build the server-side business logic of the service your mobile app provides. The reliance on HTML5, as with FeedHenry, also has the downside that you must create the user interface of your app yourself. Whereas Appcelerator provides an API for constructing the user interface, when you use HTML5, you must build the interface manually and rely on third-party libraries such as jQuery Mobile for help.

The appMobi Development Environment

You develop apps for appMobi by using your existing code editor and HTML development tools. Unlike with FeedHenry and Appcelerator, there is no appMobi-specific code editor or IDE. However, appMobi does provide you with a downloadable SDK that runs inside your web browser. This is actually a lot more useful than it sounds, and appMobi has built a really great tool. This SDK, known as appMobi XDK, provides an environment to test, manage, and deploy your apps. The app-testing capabilities of the XDK environment far exceed those of appMobi’s competitors. For example, you can specify device context, such as orientation in three-dimensional space, geolocation, and network connectivity characteristics. These test capabilities are more advanced than those provided by the native Xcode and Android emulators. If you are building an app that is heavily reliant on environmental context, then the appMobi XDK will almost certainly allow you to develop your app more rapidly. Figure 11-6 shows the XDK main screen.

You need to use your existing development tools when developing on the appMobi platform. Depending on your perspective, this could be a considered an advantage. On the other hand, more integrated environments allow you to manage your entire development process in one place, which can be more efficient. The XDK runs inside a desktop browser, which means very quick turnaround times when testing and debugging. You can also use the built-in browser debugging tools, such as the browser’s Developer Console.

Deciding to Use appMobi

The pricing structure for appMobi is based on the concept of resource “blocks,” for which you pay a few dollars each per month. Each block buys you a certain amount of capacity — whether bandwidth, storage, log entries, or other resources specific to the particular type of block. This pricing model can become quite expensive under high-volume usage but is suitable if you are a freelance developer with a smaller user base. The appMobi service in general has much less of an enterprise focus than the other two services discussed in this chapter.

The code underlying the appMobi device API is not open source. This means you have less insight into how the system works and less flexibility to tweak it to your needs. However, appMobi does provide a plug-in architecture so that you can extend your apps with native iPhone and Android components if you know Objective-C or Java.

To integrate with third-party cloud services, you need to write your own code to talk to their APIs. In most cases, this means you need to include jQuery or a similar library in your app to make HTTP calls easier. The appMobi API does not provide convenience methods for this purpose.

While appMobi does provide an analytics feature, it is relatively limited. The service allows you to create log entries that you can export. It does not provide a dashboard or summary view of the data. You can log custom events, but you have to parse them out of the log entries yourself.

The primary devices covered by the appMobi platform are iPhone and Android. The appMobi cloud services are also accessible from native apps, including BlackBerry apps. However, this is not very useful for web developers building mobile apps. For practical purposes, you can only build iPhone or Android apps using HTML5 on appMobi.

SUMMARY

This chapter covers the three leading JavaScript-based mobile app development services. It explores the advantages and disadvantages of each service, and you gained an understanding of the capabilities of each platform. You should now be in a position to decide the best strategy for building your next app — whether you need to opt for a lower-level service such as Amazon that gives you more control or whether to make use of prebuilt components and hosting from one of the companies discussed in this chapter.

In the next chapter, you’ll learn how to use social media services to enhance the user experience and usefulness of your app. You’ll also learn how to introduce viral elements into your app, which can be useful for promotional purposes.

• WHAT YOU LEARNED IN THIS CHAPTER

TOPIC KEY CONCEPTS
Cloud service types The term cloud development service covers a wide range of online services and offerings. It is useful to break these down into three broad categories: services that provide infrastructure, services that provide a software platform, and services that provide a vertical user-oriented online service. The key differences are in the level of effort you need to expend to configure and maintain the different kinds of services and the level of customization that you can achieve.
Vertical cloud services Cloud development service providers often deliver their services as discrete modules of functionality, with different pricing models. These functional modules address various vertical business requirements, such as e-commerce or analytics. Cloud development service providers allow you to pick and choose the set of modules that you need for each app. The benefit is that you do not need to develop the functionality that the module provides, and you don’t need to provision the storage or computation resources required.
FeedHenry.com The FeedHenry mobile cloud service offers a full cloud environment for building mobile apps using HTML5. FeedHenry also offers a server-side code execution platform so you can run your entire service from within FeedHenry. This service is targeted more at enterprise developers and may be suitable if you have a large client.
Appcelerator.com The Appcelerator service allows you to build mobile apps for iPhone and Android against native user interface components using JavaScript. This is done by providing you with an extensive proprietary API. Appcelerator does not have a general-purpose cloud hosting facility, but it does offer cloud modules to integrate with social media.
appMobi.com The appMobi environment is very suitable for game development, and this is a quality they promote. While the service does not provide an IDE, it does provide a comprehensive in-browser simulation environment.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.70.203