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

How-To Tutorials

7019 Articles
article-image-best-practices
Packt
23 Dec 2014
29 min read
Save for later

Best Practices

Packt
23 Dec 2014
29 min read
This article by Prabath Siriwardena, author of Mastering Apache Maven 3 focuses on best practices associated with all the core concepts. The following best practices are essential ingredients in creating a successful/productive build environment. The following criteria will help you evaluate the efficiency of your Maven project if you are mostly dealing with a large-scale, multi-module project: The time it takes for a developer to get started with a new project and add it to the build system The effort it requires to upgrade a version of a dependency across all the project modules The time it takes to build the complete project with a fresh local Maven repository The time it takes to do a complete offline build The time it takes to update the versions of Maven artifacts produced by the project, for example, from 1.0.0-SNAPSHOT to 1.0.0 The effort it requires for a completely new developer to understand what your Maven build does The effort it requires to introduce a new Maven repository The time it takes to execute unit tests and integration tests (For more resources related to this topic, see here.) Dependency management In the following example, you will notice that the dependency versions are added to each and every dependency defined in the application POM file: <dependencies>   <dependency>     <groupId>com.nimbusds</groupId>     <artifactId>nimbus-jose-jwt</artifactId>     <version>2.26</version>   </dependency>   <dependency>     <groupId>commons-codec</groupId>     <artifactId>commons-codec</artifactId>     <version>1.2</version>   </dependency> </dependencies> Imagine that you have a set of application POM files in a multi-module Maven project that has the same set of dependencies. If you have duplicated the artifact version with each and every dependency, then to upgrade to the latest dependency, you need to update all the POM files, which could easily lead to a mess. Not just that, if you have different versions of the same dependency used in different modules of the same project, then it's going to be a debugging nightmare in case of an issue. With proper dependency management, we can overcome both the previous issues. If it's a multi-module Maven project, you need to introduce the  dependencyManagement configuration element in the parent POM so that it will be inherited by all the other child modules: <dependencyManagement>   <dependencies>     <dependency>       <groupId>com.nimbusds</groupId>       <artifactId>nimbus-jose-jwt</artifactId>       <version>2.26</version>     </dependency>     <dependency>       <groupId>commons-codec</groupId>       <artifactId>commons-codec</artifactId>       <version>1.2</version>     </dependency>   </dependencies> </dependencyManagement> Once you define dependencies under the dependencyManagement section as shown in the previous code, you only need to refer a dependency by its groupId and artifactId tags. The version tag is picked from the appropriate the dependencyManagement section: <dependencies>   <dependency>     <groupId>com.nimbusds</groupId>     <artifactId>nimbus-jose-jwt</artifactId>   <dependency>     <groupId>commons-codec</groupId>     <artifactId>commons-codec</artifactId>   </dependency> </dependencies> With the previous code snippet, if you want to upgrade or downgrade a dependency, you only need to change the version of the dependency under the dependencyManagement section. The same principle applies to plugins as well. If you have a set of plugins, which are used across multiple modules, you should define them under the pluginManagement section of the parent module. In this way, you can downgrade or upgrade plugin versions seamlessly just by changing the pluginManagement section of the parent POM, as shown in the following code: <pluginManagement>   <plugins>     <plugin>       <artifactId>maven-resources-plugin</artifactId>       <version>2.4.2</version>     </plugin>     <plugin>       <artifactId>maven-site-plugin</artifactId>       <version>2.0-beta-6</version>     </plugin>     <plugin>       <artifactId>maven-source-plugin</artifactId>       <version>2.0.4</version>     </plugin>     <plugin>       <artifactId>maven-surefire-plugin</artifactId>       <version>2.13</version     </plugin   </plugins> </pluginManagement> Once you define the plugins in the pluginManagement section, as shown in the previous code, you only need to refer a plugin from its groupId (optional) and the artifactId tags. The version tag is picked from the appropriate pluginManagement section: <plugins>   <plugin>     <artifactId>maven-resources-plugin</artifactId>     <executions>……</executions>   </plugin>   <plugin>     <artifactId>maven-site-plugin</artifactId>     <executions>……</executions>   </plugin>   <plugin>     <artifactId>maven-source-plugin</artifactId>     <executions>……</executions>   </plugin>   <plugin>     <artifactId>maven-surefire-plugin</artifactId>     <executions>……</executions>   </plugin> </plugins> Defining a parent module In most of the multi-module Maven projects, there are many things that are shared across multiple modules. Dependency versions, plugins versions, properties, and repositories are only some of them. It is a common as well as a best practice to create a separate module called parent, and in its POM file, define everything in common. The packaging type of this POM file is pom. The artifact generated by the pom packaging type is itself a POM file. The following are a few examples: The Apache Axis2 project, available at http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/modules/parent/ The WSO2 Carbon project, available at https://svn.wso2.org/repos/wso2/carbon/platform/trunk/parent/ Not all the projects follow this approach. Some just keep the parent POM file under the root directory (not under the parent module). The following are a couple of examples: The Apache Synapse project, available at http://svn.apache.org/repos/asf/synapse/trunk/java/pom.xml The Apache HBase project, available at http://svn.apache.org/repos/asf/hbase/trunk/pom.xml Both approaches deliver the same results. However, the first one is much preferred. With the first approach, the parent POM file only defines the shared resources across different Maven modules in the project, while there is another POM file at the root of the project, which defines all the modules to be included in the project build. With the second approach, you define all the shared resources as well as all the modules to be included in the project build in the same POM file, which is under the project's root directory. The first approach is better than the second one, based on the separation of concerns principle. POM properties There are six types of properties that you can use within a Maven application POM file: Built-in properties Project properties Local settings Environment variables Java system properties Custom properties It is always recommended that you use properties, instead of hardcoding values in application POM files. Let''s look at a few examples. Let's take the application POM file inside the Apache Axis2 distribution module, available at http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/modules/distribution/pom.xml. This defines all the artifacts created in the Axis2 project that need to be included in the final distribution. All the artifacts share the same groupId tag as well as the version tag of the distribution module. This is a common scenario in most of the multi-module Maven projects. Most of the modules (if not all) share the same groupId tag and the version tag: <dependencies>   <dependency>     <groupId>org.apache.axis2</groupId>     <artifactId>axis2-java2wsdl</artifactId>     <version>${project.version}</version>   </dependency>   <dependency>     <groupId>org.apache.axis2</groupId>     <artifactId>axis2-kernel</artifactId>     <version>${project.version}</version>   </dependency>   <dependency>     <groupId>org.apache.axis2</groupId>     <artifactId>axis2-adb</artifactId>     <version>${project.version}</version>   </dependency> </dependencies> In the previous configuration, instead of duplicating the version element, Axis2 uses the project property ${project.version}. When Maven finds this project property, it reads the value from the project POM version element. If the project POM file does not have a version element, then Maven will try to read it from the immediate parent POM file. The benefit here is, when you upgrade your project version some day, you only need to upgrade the version element of the distribution POM file (or its parent). The previous configuration is not perfect; it can be further improved in the following manner: <dependencies>   <dependency>     <groupId>${project.groupId}</groupId>     <artifactId>axis2-java2wsdl</artifactId>     <version>${project.version}</version>   </dependency>   <dependency>     <groupId>${project.groupId}</groupId>     <artifactId>axis2-kernel</artifactId>     <version>${project.version}</version>   </dependency>   <dependency>     <groupId>${project.groupId}</groupId>     <artifactId>axis2-adb</artifactId>     <version>${project.version}</version>   </dependency> </dependencies> Here, we also replace the hardcoded value of groupId in all the dependencies with the project property ${project.groupid}. When Maven finds this project property, it reads the value from the project POM groupId element. If the project POM file does not have a groupId element, then Maven will try to read it from the immediate parent POM file. The following lists out some of the Maven built-in properties and project properties: project.version: This refers to the value of the version element of the project POM file project.groupId: This refers to the value of the groupId element of the project POM file project.artifactId: This refers to the value of the artifactId element of the project POM file project.name: This refers to the value of the name element of the project POM file project.description: This refers to the value of the description element of the project POM file project.baseUri: This refers to the path of the project's base directory The following is an example that shows the usage of this project property. Here, we have a system dependency that needs to be referred from a filesystem path: <dependency>   <groupId>org.apache.axis2.wso2</groupId>   <artifactId>axis2</artifactId>   <version>1.6.0.wso2v2</version>   <scope>system</scope>   <systemPath>${project.basedir}/lib/axis2-1.6.jar</systemPath> </dependency> In addition to the project properties, you can also read properties from the USER_HOME/.m2/settings.xml file. For example, if you want to read the path to the local Maven repository, you can use the ${settings.localRepository} property. In the same way, with the same pattern, you can read any of the configuration elements that are defined in the settings.xml file. The environment variables defined in the system can be read using the env prefix, within an application POM file. The ${env.M2_HOME} property will return the path to the Maven home, while ${env.java_home} returns the path to the Java home directory. These properties will be quite useful within certain Maven plugins. Maven also lets you define your own set of custom properties. Custom properties are mostly used when defining dependency versions. You should not scatter custom properties all over the place. The ideal place to define them is the parent POM file in a multi-module Maven project, which will then be inherited by all the other child modules. If you look at the parent POM file of the WSO2 Carbon project, you will find a large set of custom properties, which are defined in https://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/parent/pom.xml. The following lists out some of them: <properties>   <rampart.version>1.6.1-wso2v10</rampart.version>   <rampart.mar.version>1.6.1-wso2v10</rampart.mar.version>   <rampart.osgi.version>1.6.1.wso2v10</rampart.osgi.version> </properties> When you add a dependency to the Rampart JAR, you do not need to specify the version there. Just refer it by the ${rampart.version} property name. Also, keep in mind that all the custom defined properties are inherited and can be overridden in any child POM file: <dependency>   <groupId>org.apache.rampart.wso2</groupId>   <artifactId>rampart-core</artifactId>   <version>${rampart.version}</version> </dependency> Avoiding repetitive groupId  and version tags and inherit from the parent POM In a multi-module Maven project, most of the modules (if not all) share the same groupId and version elements. In this case, you can avoid adding the version and groupId elements to your application POM file. These will be automatically inherited from the corresponding parent POM. If you look at axis2-kernel (which is a module of the Apache Axis2 project), you will find that no groupId or version is defined at http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/modules/kernel/pom.xml. Maven reads them from the parent POM file: <project>   <modelVersion>4.0.0</modelVersion>   <parent>     <groupId>org.apache.axis2</groupId>     <artifactId>axis2-parent</artifactId>     <version>1.7.0-SNAPSHOT</version>     <relativePath>../parent/pom.xml</relativePath>   </parent>   <artifactId>axis2-kernel</artifactId>   <name>Apache Axis2 - Kernel</name> </project> Following naming conventions When defining coordinates for your Maven project, you must always follow the naming conventions. The value of the groupId element should follow the same naming convention you use in Java package names. It has to be a domain name (the reverse of the domain name) that you own, or at least your project is developed under. The following lists out some of the naming conventions related to groupId: The name of the groupId element has to be in lower case. Use the reverse of a domain name that can be used to uniquely identify your project. This will also help to avoid collisions between artifacts produced by different projects. Avoid using digits or special characters (that is, org.wso2.carbon.identity-core). Do not try to group two words into a single word by camel casing (that is, org.wso2.carbon.identityCore). Make sure that all the subprojects developed under different teams in the same company finally inherit from the same groupId element and extend the name of the parent groupId element rather than defining their own. Let's go through some examples. You will notice that all the open source projects developed under Apache Software Foundation (ASF) use the same parent groupId (org.apache) and define their own groupId elements, which extend from the parent: The Apache Axis2 project uses org.apache.axis2, which inherits from the org.apache parent groupId The Apache Synapse project uses org.apache.synapse, which inherits from the org.apache parent groupId The Apache ServiceMix project uses org.apache.servicemix, which inherits from the org.apache parent groupId The WSO2 Carbon project uses org.wso2.carbon Apart from the groupId element, you should also follow the naming conventions while defining artifactIds. The following lists out some of the naming conventions related to artifactId: The name of the artifactId has to be in lower case. Avoid duplicating the value of groupId inside the artifactId element. If you find a need to start your artifactId with the value of groupId element and add something to the end, then you need to revisit the structure of your project. You might need to add more module groups. Avoid using special characters (that is, #, $, &, %, and so on). Do not try to group two words into a single word by camel casing (that is, identityCore). Following naming conventions for version is also equally important. The version of a given Maven artifact can be divided into four categories: <Major version>.<Minor version>.<Incremental version>-<Build   number or the qualifier> The major version reflects the introduction of a new major feature. A change in the major version of a given artifact can also mean that the new changes are not necessarily backward compatible with the previously released artifact. The minor version reflects an introduction of a new feature to the previously released version, in a backward compatible manner. The incremental version reflects a bug-fixed release of the artifact. The build number can be the revision number from the source code repository. This versioning convention is not just for Maven artifacts. Apple did a major release of its iOS mobile operating system in September 2014: iOS 8.0.0. Soon after the release, they discovered a critical bug in it that had an impact on cellular network connectivity and TouchID on iPhone. Then, they released iOS 8.0.1 as a patch release to fix the issues. Let's go through some of the examples: The Apache Axis2 1.6.0 release, available at http://svn.apache.org/repos/asf/axis/axis2/java/core/tags/v1.6.0/pom.xml. The Apache Axis2 1.6.2 release, available at http://svn.apache.org/repos/asf/axis/axis2/java/core/tags/v1.6.2/pom.xml. Apache Axis2 1.7.0-SNAPSHOT release, available at http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/pom.xml. SNAPSHOT releases are done from the trunk of the source repository with the latest available code. Apache Synapse 2.1.0-wso2v5 release, available at http://svn.wso2.org/repos/wso2/tags/carbon/3.2.3/dependencies/synapse/2.1.0-wso2v5/pom.xml. Here, the Synapse code is maintained under the WSO2 source repository and not under the Apache repository. In this case, we use the wso2v5 classifier to make it different from the same artifact produced by Apache Synapse. Maven profiles When do we need Maven profiles and why is it a best practice? Think about a large-scale multi-module Maven project. One of the best examples I am aware of is the WSO2 Carbon project. If you look at the application POM file available at http://svn.wso2.org/repos/wso2/tags/carbon/3.2.3/components/pom.xml, you will notice that there are more than hundred modules. Also, if you go deeper into each module, you will further notice that there are more modules within them: http://svn.wso2.org/repos/wso2/tags/carbon/3.2.3/components/identity/pom.xml. As a developer of the WSO2 Carbon project, you do not need to build all these modules. In this specific example, different groups of the modules are later aggregated into build multiple products. However, a given product does not need to build all the modules defined in the parent POM file. If you are a developer in a product team, you only need to worry about building the set of modules related to your product; if not, it's an utter waste of productive time. Maven profiles help you to do this. With Maven profiles, you can activate a subset of configurations defined in your application POM file, based on some criteria. If we take the same example we took previously, you will find that multiple profiles are defined under the <profiles> element: http://svn.wso2.org/repos/wso2/tags/carbon/3.2.3/components/pom.xml. Each profile element defines the set of modules that is relevant to it and identified by a unique ID. Also for each module, you need to define a criterion to activate it, under the activation element. By setting the value of the activeByDefault element to true, we make sure that the corresponding profile will get activated when no other profile is picked. In this particular example, if we just execute mvn clean install, the profile with the default ID will get executed. Keep in mind that the magic here does not lie on the name of the profile ID, default, but on the value of the activeByDefault element, which is set to true for the default profile. The value of the id element can be of any name: <profiles>   <profile>     <id>product-esb</id>     <activation>       <property>         <name>product</name>         <value>esb</value>       </property>     </activation>     <modules></modules>   </profile>   <profile>     <id>product-greg</id>     <activation>       <property>         <name>product</name>         <value>greg</value>       </property>     </activation>     <modules></modules>   </profile>   <profile>     <id>product-is</id>     <activation>       <property>         <name>product</name>         <value>is</value>       </property>     </activation     <modules></modules>   </profile>   <profile>     <id>default</id>     <activation>       <activeByDefault>true</activeByDefault>     </activation>     <modules></modules>   </profile> </profiles> If I am a member of the WSO2 Identity Server (IS) team, then I will execute the build in the following manner: $ mvn clean install –Dproduct=is Here, we pass the system property product with the value is. If you look at the activation criteria for all the profiles, all are based on the system property: product. If the value of the system property is is, then Maven will pick the build profile corresponding to the Identity Server: <activation>   <property>     <name>product</name>     <value>is</value>   </property> </activation> You also can define an activation criterion to execute a profile, in the absence of a property. For example, the following configuration shows how to activate a profile if the product property is missing: <activation>   <property>     <name>!product</name>   </property> </activation> The profile activation criteria can be based on a system property, the JDK version, or an operating system parameter where you run the build. The following sample configuration shows how to activate a build profile for JDK 1.6: <activation>   <jdk>1.6</jdk> </activation> The following sample configuration shows how to activate a build profile based on operating system parameters: <activation>   <os>     <name>mac os x</name>     <family>mac</family>     <arch>x86_64</arch>    <version>10.8.5</version>   </os> </activation> The following sample configuration shows how to activate a build profile based on the presence or absence of a file: <activation>   <file>     <exists>……</exists>     <missing>……</missing>   </file> </activation> In addition to the activation configuration, you can also execute a Maven profile just by its ID, which is defined within the id element. In this case, you need a prefix; use the profile ID with –P, as shown in the following command: $ mvn clean install -Pproduct-is Think twice before you write your own plugin Maven is all about plugins! There is a plugin out there for almost everything. If you find a need to write a plugin, spend some time researching on the Web to see whether you can find something similar—the chances are very high. You can also find a list of available Maven plugins at http://maven.apache.org/plugins. The Maven release plugin Releasing a project requires a lot of repetitive tasks. The objective of the Maven release plugin is to automate them. The release plugin defines the following eight goals, which are executed in two stages, preparing the release and performing the release: release:clean: This goal cleans up after a release preparation release:prepare: This goal prepares for a release in Software Configuration Management (SCM) release:prepare-with-pom: This goal prepares for a release in SCM and generates release POMs by fully resolving the dependencies release:rollback: This goal rolls back to a previous release release:perform: This goal performs a release from SCM release:stage: This goal performs a release from SCM into a staging folder/repository release:branch: This goal creates a branch of the current project with all versions updated release:update-versions: This goal updates versions in the POM(s) The preparation stage will complete the following tasks with the release:prepare goal: Verify that all the changes in the source code are committed. Make sure that there are no SNAPSHOT dependencies. During the project development phase, we use SNAPSHOT dependencies but at the time of the release, all dependencies should be changed to a released version. Change the version of project POM files from SNAPSHOT to a concrete version number. Change the SCM information in the project POM to include the final destination of the tag. Execute all the tests against the modified POM files. Commit the modified POM files to the SCM and tag the code with the version name. Change the version of POM files in the trunk to a SNAPSHOT version and then commit the modified POM files to the trunk. Finally, the release will be performed with the release:perform goal. This will check the code from the release tag in the SCM and run a set of predefined goals: site, deploy-site. The maven-release-plugin is not defined in the super POM and should be explicitly defined in your project POM file. The releaseProfiles configuration element defines the profiles to be released and the goals configuration element defines the plugin goals to be executed during the release:perform goal. In the following configuration, the deploy goal of the maven-deploy-plugin and the single goal of the maven-assembly-plugin will get executed: <plugin>   <artifactId>maven-release-plugin</artifactId>   <version>2.5</version>   <configuration>     <releaseProfiles>release</releaseProfiles>     <goals>deploy assembly:single</goals>   </configuration> </plugin> More details about the Maven release plugin are available at http://maven.apache.org/maven-release/maven-release-plugin/. The Maven enforcer plugin The Maven enforcer plugin lets you control or enforce constraints in your build environment. These could be the Maven version, Java version, operating system parameters, and even user-defined rules. The plugin defines two goals: enforce and displayInfo. The enforcer:enforce goal will execute all the defined rules against all the modules in a multi-module Maven project, while enforcer:displayInfo will display the project compliance details with respect to the standard rule set. The maven-enforcer-plugin is not defined in the super POM and should be explicitly defined in your project POM file: <plugins>   <plugin>     <groupId>org.apache.maven.plugins</groupId>     <artifactId>maven-enforcer-plugin</artifactId>     <version>1.3.1</version>     <executions>       <execution>         <id>enforce-versions</id>         <goals>           <goal>enforce</goal>         </goals>         <configuration>           <rules>             <requireMavenVersion>               <version>3.2.1</version>             </requireMavenVersion>             <requireJavaVersion>               <version>1.6</version>             </requireJavaVersion>             <requireOS>               <family>mac</family>             </requireOS>           </rules>         </configuration>       </execution>     </executions>   </plugin> </plugins> The previous plugin configuration enforces the Maven version to be 3.2.1, the Java version to be 1.6, and the operating system to be in the Mac family. The Apache Axis2 project uses the enforcer plugin to make sure that no application POM file defines Maven repositories. All the artifacts required by Axis2 are expected to be in the Maven central repository. The following configuration element is extracted from http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/modules/parent/pom.xml. Here, it bans all the repositories and plugin repositories, except snapshot repositories: <plugin>   <artifactId>maven-enforcer-plugin</artifactId>   <version>1.1</version>   <executions>     <execution>       <phase>validate</phase>       <goals>         <goal>enforce</goal>       </goals>       <configuration>         <rules>           <requireNoRepositories>             <banRepositories>true</banRepositories>             <banPluginRepositories>true</banPluginRepositories>             <allowSnapshotRepositories>true</allowSnapshotRepositories>             <allowSnapshotPluginRepositories>true</allowSnapshotPluginRepositories>           </requireNoRepositories>         </rules>       </configuration>     </execution>   </executions> </plugin> In addition to the standard rule set ships with the enforcer plugin, you can also define your own rules. More details about how to write custom rules are available at http://maven.apache.org/enforcer/enforcer-api/writing-a-custom-rule.html. Avoid using un-versioned plugins If you have associated a plugin with your application POM, without a version, then Maven will download the corresponding maven-metadata.xml file and store it locally. Only the latest released version of the plugin will be downloaded and used in the project. This can easily create certain uncertainties. Your project might work fine with the current version of a plugin, but later if there is a new release of the same plugin, your Maven project will start to use the latest one automatically. This can result in unpredictable behaviors and lead to a debugging mess. It is always recommended that you specify the plugin version along with the plugin configuration. You can enforce this as a rule, with the Maven enforcer plugin, as shown in the following code: <plugin>   <groupId>org.apache.maven.plugins</groupId>   <artifactId>maven-enforcer-plugin</artifactId>   <version>1.3.1</version>   <executions>     <execution>       <id>enforce-plugin-versions</id>       <goals>         <goal>enforce</goal>       </goals>       <configuration>         <rules>           <requirePluginVersions>             <message>………… <message>             <banLatest>true</banLatest>             <banRelease>true</banRelease>             <banSnapshots>true</banSnapshots>             <phases>clean,deploy,site</phases>             <additionalPlugins>               <additionalPlugin>                 org.apache.maven.plugins:maven-eclipse-plugin               </additionalPlugin>               <additionalPlugin>                 org.apache.maven.plugins:maven-reactor-plugin               </additionalPlugin>             </additionalPlugins>             <unCheckedPluginList>               org.apache.maven.plugins:maven-enforcer-plugin,org.apache.maven.plugins:maven-idea-plugin             </unCheckedPluginList>           </requirePluginVersions>         </rules>       </configuration>     </execution>   </executions> </plugin> The following points explain each of the key configuration elements defined in the previous code: message: Use this to define an optional message to the user if the rule execution fails. banLatest: Use this to restrict the use of LATEST as the  version for any plugin. banRelease: Use this to restrict the use of RELEASE as the version for any plugin. banSnapshots: Use this to restrict the use of SNAPSHOT plugins. banTimestamps: Use this to restrict the use of SNAPSHOT plugins with the timestamp version. phases: This is a comma-separated list of phases that should be used to find lifecycle plugin bindings. The default value is clean,deploy,site. additionalPlugins: This is a list of additional plugins to enforce to have versions. These plugins might not be defined in application POM files, but are used anyway, such as help and eclipse. The plugins should be specified in the groupId:artifactId form. unCheckedPluginList: This is a comma-separated list of plugins to skip version checking. You can read more details about the requirePluginVersions rule at http://maven.apache.org/enforcer/enforcer-rules/requirePluginVersions.html. Using exclusive and inclusive routes When Maven asks for an artifact from a Nexus proxy repository, Nexus knows where to look at exactly. For example, say we have a proxy repository that runs at http://localhost:8081/nexus/content/repositories/central/, which internally points to the remote repository running at https://repo1.maven.org/maven2/. As there is one-to-one mapping between the proxy repository and the corresponding remote repository, Nexus can route the requests without much trouble. However, if Maven looks for an artifact via a Nexus group repository, then Nexus has to iterate through all the repositories in that group repository to find the exact artifact. There can be cases where we have even more than 20 repositories in a single group repository, which can easily bring delays at the client side. To optimize artifact discovery in group repositories, we need to set correct inclusive/exclusive routing rules. Avoid having both release and snapshot repositories in the same group repository With the Nexus repository manager, you can group both the release repositories and snapshot repositories together into a single group repository. This is treated as an extreme malpractice. Ideally, you should be able to define distinct update policies for release repositories and snapshot repositories. Summary In this article, we looked at and highlighted some of the best practices to be followed in a large-scale development project with Maven. It is always recommended to follow best practices, as it will drastically improve developer productivity and will reduce any maintenance nightmares. Resources for Article: Further resources on this subject: APACHE MAVEN AND M2ECLIPSE [article] Coverage With Apache Karaf Pax Exam Tests [article] Apache Karaf – Provisioning and Clusters [article]
Read more
  • 0
  • 0
  • 5835

article-image-django-debug-toolbar
Packt
20 Apr 2010
9 min read
Save for later

The Django Debug Toolbar

Packt
20 Apr 2010
9 min read
The debug toolbar has a far more advanced way of displaying the information than simply embedding it in HTML comments. The capabilities are best shown by example, so we will immediately proceed with installing the toolbar. Installing the Django Debug Toolbar The toolbar can be found on the Python package index site: https://pypi.python.org/pypi/django-debug-toolbar. Once installed, activating the debug toolbar in a Django project is accomplished with the addition of just a couple of settings. First, the debug toolbar middleware, debug_toolbar.middleware.DebugToolbarMiddleware, must be added to the MIDDLEWARE_CLASSES setting. The documentation for the toolbar notes that it should be placed after any other middleware that encodes the response content, so it is best to place it last in the middleware sequence. Second, the debug_toolbar application needs to be added to INSTALLED_APPS. The debug_toolbar application uses Django templates to render its information, thus it needs to be listed in INSTALLED_APPS so that its templates will be found by the application template loader. Third, the debug toolbar requires that the requesting IP address be listed in INTERNAL_IPS. Finally, the debug toolbar is displayed only when DEBUG is True. We've been running with debug turned on, so again we don't have to make any changes here. Note also that the debug toolbar allows you to customize under what conditions the debug toolbar is displayed. It's possible, then, to set things up so that the toolbar will be displayed for requesting IP addresses not in INTERNAL_IPS or when debug is not turned on, but for our purposes the default configuration is fine so we will not change anything. One thing that is not required is for the application itself to use a RequestContext in order for things such as the SQL query information to be available in the toolbar. The debug toolbar runs as middleware, and thus is not dependent on the application using a RequestContext in order for it to generate its information. Thus, the changes made to the survey views to specify RequestContexts on render_to_response calls would not have been needed if we started off first with the Django Debug Toolbar. Debug toolbar appearance Once the debug toolbar is added to the middleware and installed applications settings, we can see what it looks like by simply visiting any page in the survey application. Let's start with the home page. The returned page should now look something like this: Note this screenshot shows the appearance of the 0.8.0 version of the debug toolbar. Earlier versions looked considerably different, so if your results do not look like this you may be using a different version than 0.8.0. The version that you have will most likely be newer than what was available when this was written, and there may be additional toolbar panels or functions that are not covered here. As you can see, the debug toolbar appears on the right-hand side of the browser window. It consists of a series of panels that can be individually enabled or disabled by changing the toolbar configuration. The ones shown here are the ones that are enabled by default. Before taking a closer look at some of the individual panels, notice that the toolbar contains an option to hide it at the top. If Hide is selected, the toolbar reduces itself to a small tab-like indication to show that it is present: This can be very useful for cases where the expanded version of the toolbar obscures application content on the page. All of the information provided by the toolbar is still accessible, after clicking again on the DjDT tab; it is just out of the way for the moment. Most of the panels will provide detailed information when they are clicked. A few also provide summary information in the main toolbar display. As of debug toolbar version 0.8.0, the first panel listed, Django Version, only provides summary information. There is no more detailed information available by clicking on it. As you can see in the screenshot, Django 1.1.1 is the version in use here. Note that the current latest source version of the debug toolbar already provides more information for this panel than the 0.8.0 release. Since 0.8.0, this panel has been renamed to Versions, and can be clicked to provide more details. These additional details include version information for the toolbar itself and for any other installed Django applications that provide version information. The other three panels that show summary information are the Time, SQL, and Logging panels. Thus, we can see at a glance from the first appearance of the page that 60 milliseconds of CPU time were used to produce this page (111 milliseconds total elapsed time), that the page required four queries, which took 1.95 milliseconds, and that zero messages were logged during the request. In the following sections, we will dig into exactly what information is provided by each of the panels when clicked. We'll start first with the SQL panel, since it is one of the most interesting and provides the same information (in addition to a lot more). The SQL panel If we click on the SQL section of the debug toolbar, the page will change to: At a glance, this is a much nicer display of the SQL queries for the page than what we came up with earlier. The queries themselves are highlighted so that SQL keywords stand out, making them easier to read. Also, since they are not embedded inside an HTML comment, their content does not need to be altered in any way—there was no need to change the content of the query containing the double dash in order to avoid it causing display problems. (Now would probably be a good time to remove that added query, before we forget why we added it.) Notice also that the times listed for each query are more specific than what was available in Django's default query history. The debug toolbar replaces Django's query recording with its own, and provides timings in units of milliseconds instead of seconds. The display also includes a graphical representation of how long each query took, in the form of horizontal bars that appear above each query. This representation makes it easy to see when there are one or more queries that are much more expensive than the others. In fact, if a query takes an excessive amount of time, its bar will be colored red. In this case, there is not a great deal of difference in the query times, and none took particularly long, so all the bars are of similar length, and are colored gray. Digging deeper, some of the information we had to manually figure out earlier in this article is just a click away on this SQL query display. Specifically, the answer to the question of what line of our code triggered a particular SQL query to be issued. Each of the displayed queries has a Toggle Stacktrace option, which when clicked will show the stack trace associated with the query: Here we can see that all queries are made by the home method in the survey views. py file. Note that the toolbar filters out levels in the stack trace that are within Django itself, which explains why each of these has only one level shown. The first query is triggered by Line 61, which contains the filter call added to test what will happen if a query containing two dashes in a row was logged. The remaining queries are all attributed to Line 66, which is the last line of the render_to_response call in the home view. These queries, as we figured out earlier, are all made during the rendering of the template. (Your line numbers may vary from those shown here, depending on where in the file various functions were placed.) Finally, this SQL query display makes available information that we had not even gotten around to wanting yet. Under the Action column are links to SELECT, EXPLAIN, and PROFILE each query. Clicking on the SELECT link shows what the database returns when the query is actually executed. For example: Similarly, clicking on EXPLAIN and PROFILE displays what the database reports when asked to explain or profile the selected query, respectively. The exact display, and how to interpret the results, will differ from database to database. (In fact, the PROFILE option is not available with all databases—it happens to be supported by the database in use here, MySQL.) Interpreting the results from EXPLAIN and PROFILE is beyond the scope of what's covered here, but it is useful to know that if you ever need to dig deep into the performance characteristics of a query, the debug toolbar makes it easy to do so. We've now gotten a couple of pages deep into the SQL query display. How do we get back to the actual application page? Clicking on the circled >> at the upper-right of the main page display will return to the previous SQL query page, and the circled >> will turn into a circled X. Clicking the circled X on any panel detail page closes the details and returns to displaying the application data. Alternatively, clicking again on the panel area on the toolbar for the currently displayed panel will have the same effect as clicking on the circled symbol in the display area. Finally, if you prefer using the keyboard to the mouse, pressing Esc has the same effect as clicking the circled symbol. Now that we have completely explored the SQL panel, let's take a brief look at each of the other panels provided by the debug toolbar. The Time panel Clicking on the Time panel brings up more detailed information on where time was spent during production of the page: The total CPU time is split between user and system time, the total elapsed (wall clock) time is listed, and the number of voluntary and involuntary context switches are displayed. For a page that is taking too long to generate, these additional details about where the time is being spent can help point towards a cause. Note that the detailed information provided by this panel comes from the Python resource module. This is a Unix-specific Python module that is not available on non-Unix-type systems. Thus on Windows, for example, the debug toolbar time panel will only show summary information, and no further details will be available.
Read more
  • 0
  • 0
  • 5833

article-image-mobile-application-development-ibm-worklight
Packt
18 Feb 2014
13 min read
Save for later

Mobile application development with IBM Worklight

Packt
18 Feb 2014
13 min read
(For more resources related to this topic, see here.) The mobile industry is evolving rapidly with an increasing number of mobile devices, such as smartphones and tablets. People are accessing more services from mobile devices than ever before. Mobile solutions are directly impacting businesses, organizations, and their growing number of customers and partners. Even employees now expect to access services on a mobile river. Several approaches currently exist for mobile application development; which include: Web Development: Uses open web (HTML5, JavaScript) client programming modules. Hybrid Development: The app source code consists of web code executed within a native container that is provided by Worklight and consist of native libraries. Hybrid Mixed: The developer uses arguments in the web code with native language to create unique features and access native APIs that are not yet available via JavaScript, such as AR, NFC, and others. Native Development: In this approach, the application is developed using native languages or transcoded into a native language via MAP tool's native appearance device capabilities, and performance. To achieve a similar application in different platforms, requires a different level of expertise hitting the cost, time, and complexity. The preceding list outlines the major aspects of the development approaches. Reviewing this list can help you choose which development approach is correct for your particular mobile application. The IBM Worklight solution In 2012, IBM acquired its very first set of mobile development and integration tools called IBM Worklight, which allows organizations to transform their business and deliver mobile solutions to their customers. IBM Worklight provides a truly open approach for developers to build an application and run it across multiple mobile platforms without having to port it for each environment, that is, Apple iOS, Google Android, Blackberry, and Microsoft Windows Phone. IBM Worklight also makes the developer's life easier by using standard technologies such as HTML5 and JavaScript with extensions for popular libraries such as jQuery Mobile, Dojo Toolkit, and Sencha Touch. IBM Worklight is a mobile application platform containing all of the tools needed to develop a mobile application. If we combine IBM Worklight components into a stream, it would be clean to say that hybrid mobile application development is tightly coupled with a baseline. Every specified component provides a bundle of functionalities and supports. Here is the lifecycle of Mobile Application Development; Worklight Studio: IBM Worklight provides a robust development Eclipse based environment called Worklight Studio that allow developers to quickly construct mobile application for multiple operating platforms. Worklight Server: This component is a runtime server that activates or enables secure data transmission through centralized back-end connectivity with adapters, used for offline encrypted storage, unified Push Notification and many more. Worklight Device Runtime: The device runtime provides a rich set of APIs that are cross-platform in nature and offer easy access to the services provided by the IBM Worklight Server. Worklight Console: This is a web dependent interface for real-time analytics, Managing Push Notification Authority and Mobile Version Management. The Worklight Console is a web-based interface and dedicated for ongoing administration of Worklight Server and its deployed apps, adapters and push notification services. Worklight Application Center: It's a cross-platform Mobile Application Store which pretends specific needs for Mobile Application Development team. There is a big advantage for using Worklight to creating user interface and that reflects on development at client side as well as server side. In general developer faces problems during development and support for creation of hybrid app by using other product, are typical not straight to define the use cases, debugging, preview testing for enterprise application but using a Worklight, developer can make simple architecture and enhanced improvised structures are amend to have mobile application. Creating a Simple IBM Worklight Application Let's start by creating a simple HelloWorld Worklight project; The steps described for creating an app are similar for IBM Worklight Studio and Eclipse IDE. The following is what you'll need to do: Start IBM Worklight Studio. Navigate to File| New and select Worklight Project, as shown in the following screenshot: Create New Worklight Project In the dialog that is displayed in the following screenshot, select Hybrid Application as the type of application defined in project templates, enter HelloWorld as the name of the first mobile project, and click on Next. Asked for Worklight Project Name and Project Type. You will see another dialog for Hybrid Application. In Application name, provide HelloWorld as the name of the application. Leave the checkboxes unchecked for now; these are used to extend supported JavaScript libraries into the app. Click on Finish. Define Worklight App Name in the window After clicking on Finish, you will see your project has been created from design perspective in Project Explorer, as shown in the following screenshot: Project Explore after complete Wizard. Adding an environment We have covered IBM Worklight Studio features and what they offer developers. It's time to see how this tool and plugin will make your life even easier. The cross platform development feature is a great deal to implement. It provides you with the means to achieve cross-development environment without any hurdles and with just a few clicks within its efficient interface. To add an environment for Android, iPhone, or any other platform, right-click on the Apps folder next to the adapters and navigate to New| Worklight Environment. You will see that a dialog box appears with checkboxes for currently supported environments, which you need to create an application for. The following screenshot illustrates this feature—we're adding an Android environment for this application: Worklight Environment selection window IBM Worklight Client Side API In this article, you will learn how the IBM Worklight client-side API can improve mobile application development. You will also see the IBM Worklight server side API improve client/server integration and communication between mobile applications and back end systems. The IBM Worklight client-side API allows mobile applications to access most of the features that are available in IBM Worklight during runtime, in order to get access to some defined libraries that appear to be bundled into the mobile application. Integration of the libraries for your mobile application using Worklight Server is used to access predefined communication interfaces. These libraries also offer unified access to native device features, which streamlines application development. The IBM Worklight client-side API contains hybrid, native, mixed hybrid, and web-based APIs. Besides, it extends those of these APIs that are responsible for supporting every mobile development framework. The development framework for a mobile application is used to improve security including custom and built-in authentication mechanisms for IBM Worklight provided by client-side API modules. It provides a semantic connection between web technologies such as HTML5, CSS3, and JavaScript with native functions that are available for different mobile platforms. Exploring Dojo Mobile Regarding the Dojo UI framework, you'll learn about Dojo Mobile in detail. Dojo Mobile, an extension for Dojo Toolkit, provides a series of widgets, or components, optimized for use on a mobile device, such as a smartphone or tablet. The Dojo framework is an extension of JavaScript and provides a built-in library which contains custom components such as text fields, validation menus, and image galleries. The components are modelled on their native counterparts and will look and feel native to those familiar with smartphone applications. The components are completely customizable using themes that let you make various customizations, such as pushing different sets of styles to iOS and Android users. Authentication and Security Modules Worklight has built-in authentication framework that allows developer to configure and use it with very little effort. The Worklight project has an authentication configuration file, which is used to declare and force security on mobile application, adapters, data and web resources which consist following security entities. We will talk about the various pre-defined authentication realms and security tests that are provided in Worklight out-of-box. To identify the importance of Mobile security you can see that in today's life we keep our personal and business data on mobile devices. The data and applications are both important to us. Both the data and applications should be protected against unauthorized access, particularly if they contain sensitive information or transmitting over the network. There are number of ways via a device can be compromised and it can leak data to malicious users. Worklight security principles, concepts and terminology IBM Worklight provides various security roles to protect applications, adapter procedures, and static resources from an unauthorized access. Each role can be defined by a security test that comprises one or more authentication realms. The authentication realm defines a process that will be used to authenticate the users. The authentication realm has the following parts: Challenge handler: This is a component on the device side Authenticator and login module: This is a component on the server One authentication realm can be used to protect multiple resources. We will look into each component in detail. Device Request Flow: The following screenshot shows a device that makes a request to access a protected resource, for example, an adapter function, on the server. In response to the request, the server sends back an authentication challenge to the device to submit its authenticity: Request/Response flow between Worklight application and enterprise server diagram> Push notification Mobile OS vendors such as Apple, Google, Microsoft, and others provide a free of cost feature through which a message can be delivered to any device running on the respective OS. The OS vendors send a message commonly known as a push message to a device for a particular app. It is not required for an app to be running in order to receive a push message. A push message can contain the following: Alerts: These would appear in the form of text messages Badges: These are small, circular marks on the app icon Sounds: These are audio alerts Alerts - Text Messages Messages will appear in the notification center (for iOS) and notification bar (for Android). IBM Worklight provides a unified push notification architecture that simplifies sending push messages across multiple devices running on different platforms. It provides a central management console to manage mobile vendor services, for example, APNS and GCM, in the background. Worklight provides the following push notification benefits: Easy to use: Users can easily subscribe and unsubscribe to a push service Quick message delivery: The push message gets delivered to a user's device even if the app is currently not running on the device Message feedback: It is possible to send feedback whenever a user receives and reads a push message Cordova Plugins A Cordova plugin is an open source, cross-platform mobile development architecture that allows the creation of multiplatform-deployable mobile apps. These apps can access native component features of devices using an API having web technologies such as HTML 5, JavaScript, and CSS 3. Apache Cordova Plugins are integrated into IBM Worklight Android and iOS projects. In this article, we will describe how Apache Cordova leverages the ability to merge the JavaScript interface as a wrapper on the web side in a native container with the device native interface on the mobile device platform. The most critical aspect of Cordova plugins is to deal with the native functionalities such as camera, bar code scanning, contacts list, and many other native features, currently running on multiple platforms. JavaScript doesn't provide such extensibility to enhance the scripting with respect to the native devices. In order to have a native feature's accessibility, we provide a library corresponding to the device's native feature so that JavaScript can communicate through it. When the need arises for a web page to execute the native feature functionality, the following points of access are available: The scenario has to be implemented in platform-specific manner, for example, in Android, iOS, or any other device In order to handle requests and responses between web pages and native pages, we need to communicate to/from web and native pages that are encrypted. By selecting the first option from the preceding list, we would find ourselves implementing and developing platform-dependent mobile applications. As we are in need of implementing mobile applications for a cross-platform mobile, and because it leads to provide cost-ineffective solutions, it is not a wise choice for Enterprise Mobile Development Solutions. It seems to be a really poor extensible for future enhancements and needs. Encrypted Offline Cache Encrypted Offline Cache (EOC) is the mechanism that is used for storing the repeated and the most sensitive data, which is used in the client's application. Encrypted Offline Cache is precisely known as EOC. It permits a flexible on-device data storage procedure for Android, iOS, BlackBerry, and Windows. This procedure provides a better alternative to the user for storing the manipulated data or the fetched response using the defined adapter data when offline and synchronizing the data for the usage of the server, which provides modifications that were completely developed when offline or without Internet connectivity. In order to dedicatedly create any mobile application for multiple platforms such as iOS and Android, consider using JSONStore rather than EOC. It seems to be much more practical to implement and is supposed to be the best practices of IBM. The JSONStore provides a mechanism to ease cryptographic procedures for encrypting forms and implementing security. PBKDF2 is a key derivation function that would act as the password to access encrypted data, which would be provided by the user. HTML5 cache can be used in EOC, which is not guaranteed to be persistent and is not a proper solution for the future updated versions of iOS. Storage JSONStore The local replica is a JSONStore. IBM Worklight delivers an API which do its work with a JSON Store consuming the class WL.JSONStore using the JavaScript defined method. You can generate an application that endures a local storage manipulated data with data copy and thrusts the local updates to a back-end provisioned service. Nearly every single method or process which is delivered in API for retrieving synchronized data to activate the native copy of the defined data that is kept on the client application or on-device. By means of the JSONStore API, you can encompass the functionality of existing adapter connectivity model to store data locally and impulse modifications from the client to a server. You can pursuit the local data storage and apprise or delete data within it. It can be used to protect the local data store by using password-based encryption. Summary In this article, we have discussed modern world mobile development techniques using IBM Worklight which surely allows an easy ,integrated, and secure enterprise mobile application with respect to time and development efforts. Beside it, most of the key functional areas have been covered including IBM Worklight components, mobile cross-platform environment handling and authentication, push notifications, Dojo mobile framework, and Encrypted Cache for Offline storage. IBM Worklight has the most diverse mechanism to enhance the mobile application functionalities with a more optimum and efficient way. This article also completely concludes the mobile application development techniques and features, by using which enterprise mobile app development will no longer be disquiet. Resources for Article: Further resources on this subject: Creating and configuring a basic mobile application [Article] Viewing on Mobile Devices [Article] Creating mobile friendly themes [Article]
Read more
  • 0
  • 0
  • 5831

article-image-using-sprites-animation
Packt
03 Oct 2013
6 min read
Save for later

Using Sprites for Animation

Packt
03 Oct 2013
6 min read
(For more resources related to this topic, see here.) Sprites Let's briefly discuss sprites. In gaming, sprites are usually used for animation sequences; a sprite is a single image in which individual frames of a character animation are stored. We are going use sprites in our animations. If you already have knowledge of graphics design, it's good for you because it is an edge for you to define how you want your game to look like and how you want to define animation sequences in sprites. You can try out tools such as Sprite Maker for making your own sprites with ease; you can get a copy of Sprite Maker at http://www.spriteland.com/sprites/sprite-maker.zip. The following is an sample animation sprite by Marc Russell, which is available for free at http://opengameart.org/content/gfxlib-fuzed you can find other open source sprites at http://opengameart.org/content/platformersidescroller-tiles: The preceding sprite will play the animation of the character moving to the right. The character sequence is well organized using an invisible grid, as shown in the following screenshot: The grid is 32 x 32; the size of our grid is very important in setting up the quads for our game. A quad in LÖVE is a specific part of an image. Because our sprite is a single image file, quads will be used to specify each of the sequences we want to draw per unit time and will be the largest part part of our animation algorithm. Animation The animation algorithm will simply play the sprite like a tape of film; we'll be using a basic technique here as LÖVE doesn't have an official module for that. Some members of the LÖVE forum have come up with different libraries to ease the way we play animations. First of all let us load our file: function love.load() sprite = love.graphics.newImage "sprite.png" end Then we create quads for each part of the sprite by using love.graphics. newQuad(x, y, width, height, sw, sh), where x is the top-left position of the quad along the x axis, y is the top-left position of the quad along the y axis, width is the width of the quad, height is the height of the quad, sw is the sprite's width, and sh is the sprite's height: love.graphics.newQuad(0, 0, 32, 32, 256, 32) --- first quad love.graphics.newQuad(32, 0, 32, 32, 256, 32) --- second quad love.graphics.newQuad(64, 0, 32, 32, 256, 32) --- Third quad love.graphics.newQuad(96, 0, 32, 32, 256, 32) --- Fourth quad love.graphics.newQuad(128, 0, 32, 32, 256, 32) --- Fifth quad love.graphics.newQuad(160, 0, 32, 32, 256, 32) --- Sixth quad love.graphics.newQuad(192, 0, 32, 32, 256, 32) --- Seventh quad love.graphics.newQuad(224, 0, 32, 32, 256, 32) --- Eighth quad The preceding code can be rewritten in a more concise loop as shown in the following code snippet: for i=1,8 do love.graphics.newQuad((i-1)*32, 0, 32, 32, 256, 32) end As advised by LÖVE, we shouldn't state our quads in the draw() or update() functions, because it will cause the quad data to be repeatedly loaded into memory with every frame, which is a bad practice. So what we'll do is pretty simple; we'll load our quad parameters in a table, while love.graphics.newQuad will be referenced locally outside the functions. So the new code will look like the following for the animation in the right direction: local Quad = love.graphics.newQuad function love.load() sprite = love.graphics.newImage "sprite.png" quads = {} quads['right'] ={} quads['left'] = {} for j=1,8 do quads['right'][j] = Quad((j-1)*32, 0, 32, 32, 256, 32); quads['left'][j] = Quad((j-1)*32, 0, 32, 32, 256, 32); -- for the character to face the opposite direction, the quad need to be flipped by using the Quad:flip(x, y) method, where x and why are Boolean. quads.left[j]:flip(true, false) --flip horizontally x = true, y = false end end Now that our animation table is set, it is important that we set a Boolean value for the state of our character. At the start of the game our character is idle, so we set idle to true. Also, there are a number of quads the algorithm should read in order to play our animation. In our case, we have eight quads, so we need a maximum of eight iterations, as shown in the following code snippet: local Quad = love.graphics.newQuad function love.load() character= {} character.player = love.graphics.newImage("sprite.png") character.x = 50 character.y = 50 direction = "right" iteration = 1 max = 8 idle = true timer = 0.1 quads = {} quads['right'] ={} quads['left'] = {} for j=1,8 do quads['right'][j] = Quad((j-1)*32, 0, 32, 32, 256, 32); quads['left'][j] = Quad((j-1)*32, 0, 32, 32, 256, 32); -- for the character to face the opposite direction, the quad need to be flipped by using the Quad:flip(x, y) method, where x and why are Boolean. quads.left[j]:flip(true, false) --flip horizontally x = true, y = false end end Now let us update our motion; if a certain key is pressed, the animation should play; if the key is released, the animation should stop. Also, if the key is pressed, the character should change position. We'll be using the love.keypressed callback function here, as shown in the following code snippet: function love.update(dt) if idle == false then timer = timer + dt if timer > 0.2 then timer = 0.1 -- The animation will play as the iteration increases, so we just write iteration = iteration + 1, also we'll stop reset our iteration at the maximum of 8 with a timer update to keep the animation smooth. iteration = iteration + 1 if love.keyboard.isDown('right') then sprite.x = sprite.x + 5 end if love.keyboard.isDown('left') then sprite.x = sprite.x - 5 end if iteration > max then iteration = 1 end end end end function love.keypressed(key) if quads[key] then direction = key idle = false end end function love.keyreleased(key) if quads[key] and direction == key then idle = true iteration = 1 direction = "right" end end Finally, we can draw our character on the screen. Here we'll be using love.graphics.drawq(image, quad, x, y), where image is the image data, quad will load our quads table, x is the position in x axis and y is the position in the y axis: function love.draw() love.graphics.drawq(sprite.player, quads[direction][iteration], sprite.x, sprite.y) end So let's package our game and run it to see the magic in action by pressing the left or right navigation key: Summary That is all for this article. We have learned how to draw 2D objects on the screen and move the objects in four directions. We have delved into the usage of sprites for animations and how to play these animations with code. Resources for Article: Further resources on this subject: Panda3D Game Development: Scene Effects and Shaders [Article] Microsoft XNA 4.0 Game Development: Receiving Player Input [Article] Introduction to Game Development Using Unity 3D [Article]
Read more
  • 0
  • 0
  • 5818

article-image-storage-policy-based-management
Packt
07 Sep 2015
10 min read
Save for later

Storage Policy-based Management

Packt
07 Sep 2015
10 min read
In this article by Jeffery Taylor, the author of the book VMware Virtual SAN Cookbook, we have a functional VSAN cluster, we can leverage the power of Storage Policy-based Management (SPBM) to control how we deploy our virtual machines (VMs).We will discuss the following topics, with a recipe for each: Creating storage policies Applying storage policies to a new VM or a VM deployed from a template Applying storage policies to an existing VM migrating to VSAN Viewing a VM's storage policies and object distribution Changing storage policies on a VM already residing in VSAN Modifying existing storage policies (For more resources related to this topic, see here.) Introduction SPBM is where the administrative power of converged infrastructure becomes apparent. You can define VM-thick provisioning on a sliding scale, define how fault tolerant the VM's storage should be, make distribution and performance decisions, and more. RAID-type decisions for VMs resident on VSAN are also driven through the use of SPBM. VSAN can provide RAID-1 (mirrored) and RAID-0 (striped) configurations, or a combination of the two in the form of RAID-10 (mirrored set of stripes). All of this is done on a per-VM basis. As the storage and compute infrastructures are now converged, you can define how you want a VM to run in the most logical place—at the VM level or its disks. The need for a datastore-centric configuration, storage tiering, and so on is obviated and made redundant through the power of SPBM. Technically, the configuration of storage policies is optional. If you choose not to define any storage policies, VSAN will create VMs and disks according to its default cluster-wide storage policy. While this will provide for generic levels of fault tolerance and performance, it is strongly recommended to create and apply storage policies according to your administrative need. Much of the power given to you through a converged infrastructure and VSAN is in the policy-driven and VM-centric nature of policy-based management.While some of these options will be discussed throughout the following recipes, it is strongly recommended that you review the storage-policy appendix to familiarize yourself with all the storage-policy options prior to continuing. Creating VM storage policies Before a storage policy can be applied, it must be created. Once created, the storage policy can be applied to any part of any VM resident on VSAN-connected storage. You will probably want to create a number of storage policies to suit your production needs. Once created, all storage policies are tracked by vCenter and enforced/maintained by VSAN itself. Because of this, your policy selections remain valid and production continues even in the event of a vCenter outage. In the example policy that we will create in this recipe, the VM policy will be defined as tolerating the failure of a single VSAN host. The VM will not be required to stripe across multiple disks and it will be 30percent thick-provisioned. Getting ready Your VSAN should be deployed and functional as per the previous article. You should be logged in to the vSphere Web Client as an administrator or as a user with rights to create, modify, apply, and delete storage policies. How to do it… From the vSphere 5.5 Web Client, navigate to Home | VM Storage Policies. From the vSphere 6.0 Web Client, navigate to Home | Policies and Profiles | VM Storage Policies. Initially, there will be no storage policies defined unless you have already created storage policies for other solutions. This is normal. In VSAN 6.0, you will have the VSAN default policy defined here prior to the creation of your own policies. Click the Create a new VM storage policy button:   A wizard will launch to guide you through the process. If you have multiple vCenter Server systems in linked-mode, ensure that you have selected the appropriate vCenter Server system from the drop-down menu. Give your storage policy a name that will be useful to you and a description of what the policy does. Then, click Next:   The next page describes the concept of rule sets and requires no interaction. Click the Next button to proceed. When creating the rule set, ensure that you select VSAN from the Rules based on vendor-specific capabilities drop-down menu. This will expose the <Add capability> button. Select Number of failures to tolerate from the drop-down menu and specify a value of 1:   Add other capabilities as desired. For this example, we will specify a single stripe with 30% space reservation. Once all required policy definitions have been applied, click Next:   The next page will tell you which datastores are compatible with the storage policy you have created. As this storage policy is based on specific capabilities exposed by VSAN, only your VSAN datastore will appear as a matching resource. Verify that the VSAN datastore appears, and then click Next. Review the summary page and ensure that the policy is being created on the basis of your specifications. When finished, click Finish. The policy will be created. Depending on the speed of your system, this operation should be nearly instantaneous but may take several seconds to finish. How it works… The VSAN-specific policy definitions are presented through VMware Profile-Driven Storage service, which runs with vCenter Server. Profile-Driven Storage Service determines which policy definitions are available by communicating with the ESXi hosts that are enabled for VSAN. Once VSAN is enabled, each host activates a VASA provider daemon, which is responsible for communicating policy options to and receiving policy instructions from Profile-Driven Storage Service. There's more… The nature of the storage policy definitions enabled by VSAN is additive. No policy option mutually excludes any other, and they can be combined in any way that your policy requirements demand. For example, specifying a number of failures to tolerate will not preclude the specification cache reservation. See also For a full explanation of all policy options and when you might want to use them Applying storage policies to a new VM or a VM deployed from a template When creating a new VM on VSAN, you will want to apply a storage policy to that VM according to your administrative needs. As VSAN is fully integrated into vSphere and vCenter, this is a straightforward option during the normal VM deployment wizard. The workflow described in this recipe is for creating a new VM on VSAN. If deployed from a template, the wizard process is functionally identical from step 4 of the How to do it… section in this recipe. Getting ready You should be logged into vSphere Web Client as an administrator or a user authorized to create virtual machines. You should have at least one storage policy defined (see previous recipe). How to do it… Navigate to Home | Hosts and Clusters | Datacenter | Cluster. Right-click the cluster, and then select New Virtual Machine…:   In the subsequent screen, select Create a new virtual machine. Proceed through the wizard through Step 2b. For the compute resource, ensure that you select your VSAN cluster or one of its hosts:   On the next step, select one of the VM storage policies that you created in the previous recipe. Once you select a VSAN storage policy, only the VSAN datastore will appear as compatible. Any other datastores that you have present will be ineligible for selection:   Complete the rest of the VM-deployment wizard as you normally would to select the guest OS, resources, and so on. Once completed, the VM will deploy and it will populate in the inventory tree on the left side. The VM summary will reflect that the VM resides on the VSAN storage:   How it works… All VMs resident on the VSAN storage will have a storage policy applied. Selecting the appropriate policy during VM creation means that the VM will be how you want it to be from the beginning of the VM's life. While policies can be changed later, this could involve a reconfiguration of the object, which can take time to complete and can result in increased disk and network traffic once it is initiated. Careful decision making during deployment can help you save time later. Applying storage policies to an existing VM migrating to VSAN When introducing VSAN into an existing infrastructure, you may have existing VMs that reside on the external storage, such as NFS, iSCSI, or Fibre Channel (FC). When the time comes to move these VMs into your converged infrastructure and VSAN, we will have to make policy decisions about how these VMs should be handled. Getting ready You should be logged into vSphere Web Client as an administrator or a user authorized to create, migrate, and modify VMs. How to do it… Navigate to Home | Hosts and Clusters | Datacenter | Cluster. Identify the VM that you wish to migrate to VSAN. For the example used in this recipe, we will migrate the VM called linux-vm02 that resides on NFS Datastore. Right-click the VM and select Migrate… from the context menu:   In the resulting page, select Change datastore or Change both host and datastore as applicable, and then click Next. If the VM does not already reside on one of your VSAN-enabled hosts, you must choose the Change both host and datastore option for your migration. In the next step, select one of the VM storage policies that you created in the previous recipe. Once you select a VSAN storage policy, only the VSAN datastore will appear as compatible. Any other datastores that you have present will be ineligible for selection:   You can apply different storage policies to different VM disks. This can be done by performing the following steps: Click on the Advanced >> button to reveal various parts of the VM: Once clicked, the Advanced >> button will change to << Basic.   In the Storage column, click the existing datastore to reveal a drop-down menu. Click Browse. In the subsequent window, select the desired policy from the VM Storage Policy drop-down menu. You will find that the only compatible datastore is your VSAN datastore. Click OK:   Repeat the preceding step as needed for other disks and the VM configuration file. After performing the preceding steps, click on Next. Review your selection on the final page, and then click Finish. Migrations can potentially take a long time, depending on how large the VM is, the speed of the network, and other considerations. Please monitor the progress of your VM relocation tasks using the Recent Tasks pane:   Once the migration task finishes, the VM's Summary tab will reflect that the datastore is now the VSAN datastore. For the example of this VM, the VM moved from NFS Datastore to vsanDatastore:   How it works… Much like the new VM workflow, we select the storage policy that we want to use during the migration of the VM to VSAN. However, unlike the deploy-from-template or VM-creation workflows, this process requires none of the VM configuration steps. We only have to select the storage policy, and then SPBM instructs VSAN how to place and distribute the objects. All object-distribution activities are completely transparent and automatic. This process can be used to change the storage policy of a VM already resident in the VSAN cluster, but it is more cumbersome than modifying the policies by other means. Summary In this article, we learned that storage policies give you granular control over how the data for any given VM or VM disk is handled. Storage policies allow you to define how many mirrors (RAID-1) and how many stripes (RAID-0) are associated with any given VM or VM disk. Resources for Article: Further resources on this subject: Working with Virtual Machines [article] Virtualization [article] Upgrading VMware Virtual Infrastructure Setups [article]
Read more
  • 0
  • 0
  • 5818

article-image-chrome-custom-tabs
Packt
17 Feb 2016
16 min read
Save for later

Chrome Custom Tabs

Packt
17 Feb 2016
16 min read
Well, most of us know tabs from every day Internet browsing. It doesn't really matter which browser you use; all browsers support tabs and multiple tabs' browsing. This allows us to have more than one website open at the same time and navigate between the opened instances. In Android, things are much the same, but when using WebView, you don't have tabs. This article will give highlights about WebView and the new feature of Android 6, Chrome custom tabs. (For more resources related to this topic, see here.) What is WebView? WebView is the part in the Android OS that's responsible for rendering web pages in most Android apps. If you see web content in an Android app, chances are you're looking at WebView. The major exceptions to this rule are some of the Android browsers, such as Chrome, Firefox, and so on. In Android 4.3 and lower, WebView uses code based on Apple's Webkit. In Android 4.4 and higher, WebView is based on the Chromium project, which is the open source base of Google Chrome. In Android 5.0, WebView was decoupled into a separate app that allowed timely updates through Google Play without requiring firmware updates to be issued, and the same technique was used with Google Play services. Now, let's talk again about a simple scenario: we want to display web content (URL-related) in our application. We have two options: either launch a browser or build our own in-app browser using WebView. Both options have trade-offs or disadvantages if we write them down. A browser is an external application and you can't really change its UI; while using it, you push the users to other apps and you may lose them in the wild. On the other hand, using WebView will keep the users tightly inside. However, actually dealing with all possible actions in WebView is quite an overhead. Google heard our rant and came to the rescue with Chrome custom tabs. Now we have better control over the web content in our application, and we can stitch web content into our app in a cleaner, prettier manner. Customization options Chrome custom tabs allow several modifications and tweaks: The toolbar color Enter and exit animations Custom actions for the toolbar and overflow menu Prestarted and prefetched content for faster loading When to use Chrome custom tabs Ever since WebView came out, applications have been using it in multiple ways, embedding content—local static content inside the APK and dynamic content as loading web pages that were not designed for mobile devices at the beginning. Later on we saw the rise of the mobile web era complete with hybrid applications). Chrome custom tabs are a bit more than just loading local content or mobile-compatible web content. They should be used when you load web data and want to allow simple implementation and easier code maintenance and, furthermore, make the web content part of your application—as if it's always there within your app. Among the reasons why you should use custom tabs are the following: Easy implementation: you use the support library when required or just add extras to your View intent. It's that simple. In app UI modifications, you can do the following: Set the toolbar color Add/change the action button Add custom menu items to the overflow menu Set and create custom in/out animations when entering the tab or exiting to the previous location Easier navigation and navigation logic: you can get a callback notifying you about an external navigation, if required. You know when the user navigates to web content and where they should return when done. Chrome custom tabs allow added performance optimizations that you can use: You can keep the engine running, so to speak, and actually give the custom tab a head start to start itself and do some warm up prior to using it. This is done without interfering or taking away precious application resources. You can provide a URL to load in advance in the background while waiting for other user interactions. This speeds up the user-visible page loading time and gives the user a sense of blazing fast application where all the content is just a click away. While using the custom tab, the application won't be evicted as the application level will still be in the foreground even though the tab is on top of it. So, we remain at the top level for the entire usage time (unless a phone call or some other user interaction leads to a change). Using the same Chrome container means that users are already signed in to sites they connected to in the past; specific permissions that were granted previously apply here as well; even fill data, autocomplete, and sync work here. Chrome custom tabs allow us give the users the latest browser implementation on pre-Lollipop devices where WebView is not the latest version. The implementation guide As discussed earlier, we have a couple of features integrated into Chrome custom tabs. The first customizes the UI and interaction with the custom tabs. The second allows pages to be loaded faster and keeps the application alive. Can we use Chrome custom tabs? Before we start using custom tabs, we want to make sure they're supported. Chrome custom tabs expose a service, so the best check for support is to try and bind to the service. Success means that custom tabs are supported and can be used. You can check out this gist, which shows a helper how to to check it, or check the project source code later on at https://gist.github.com/MaTriXy/5775cb0ff98216b2a99d. After checking and learning that support exists, we will start with the UI and interaction part. Custom UI and tab interaction Here, we will use the well-known ACTION_VIEW intent action, and by appending extras to the intent sent to Chrome, we will trigger changes in the UI. Remember that the ACTION_VIEW intent is compatible with all browsers, including Chrome. There are some phones without Chrome out there, or there are instances where the device's default browser isn't Chrome. In these cases, the user will navigate to the specific browser application. Intent is a convenient way to pass that extra data we want Chrome to get. Don't use any of these flags when calling to the Chrome custom tabs: FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_DOCUMENT Before using the API, we need to add it to our gradle file: compile 'com.android.support:customtabs:23.1.0' This will allow us to use the custom tab support library in our application: CustomTabsIntent.EXTRA_SESSION The preceding code is an extra from the custom tabs support library; it's used to match the session. It must be included in the intent when opening a custom tab. It can be null if there is no need to match any service-side sessions with the intent. We have a sample project to show the options for the UI called ChubbyTabby at https://github.com/MaTriXy/ChubbyTabby. We will go over the important parts here as well. Our main interaction comes from a special builder from the support library called CustomTabsIntent.Builder; this class will help us build the intent we need for the custom tab: CustomTabsIntent.Builder intentBuilder = new CustomTabsIntent.Builder(); //init our Builder //Setting Toolbar Color int color = getResources().getColor(R.color.primary); //we use primary color for our toolbar as well - you can define any color you want and use it. intentBuilder.setToolbarColor(color); //Enabling Title showing intentBuilder.setShowTitle(true); //this will show the title in the custom tab along the url showing at the bottom part of the tab toolbar. //This part is adding custom actions to the over flow menu String menuItemTitle = getString(R.string.menu_title_share); PendingIntent menuItemPendingIntent = createPendingShareIntent(); intentBuilder.addMenuItem(menuItemTitle, menuItemPendingIntent); String menuItemEmailTitle = getString(R.string.menu_title_email); PendingIntent menuItemPendingIntentTwo = createPendingEmailIntent(); intentBuilder.addMenuItem(menuItemEmailTitle, menuItemPendingIntentTwo); //Setting custom Close Icon. intentBuilder.setCloseButtonIcon(mCloseButtonBitmap); //Adding custom icon with custom action for the share action. intentBuilder.setActionButton(mActionButtonBitmap, getString(R.string.menu_title_share), createPendingShareIntent()); //Setting start and exit animation for the custom tab. intentBuilder.setStartAnimations(this, R.anim.slide_in_right, R.anim.slide_out_left); intentBuilder.setExitAnimations(this, android.R.anim.slide_in_left, android.R.anim.slide_out_right); CustomTabActivityHelper.openCustomTab(this, intentBuilder.build(), Uri.parse(URL), new WebviewFallback(), useCustom);  A few things to notice here are as follows: Every menu item uses a pending intent; if you don't know what a pending intent is, head to http://developer.android.com/reference/android/app/PendingIntent.html When we set custom icons, such as close buttons or an action button, for that matter, we use bitmaps and we must decode the bitmap prior to passing it to the builder Setting animations is easy and you can use animations' XML files that you created previously; just make sure that you test the result before releasing the app The following screenshot is an example of a Chrome custom UI and tab: The custom action button As developers, we have full control over the action buttons presented in our custom tab. For most use cases, we can think of a share action or maybe a more common option that your users will perform. The action button is basically a bundle with an icon of the action button and a pending intent that will be called by Chrome when your user hits the action button. The icon should be 24 dp in height and 24-48 dp in width according to specifications: //Adding custom icon with custom action for the share action intentBuilder.setActionButton(mActionButtonBitmap, getString(R.string.menu_title_share), createPendingShareIntent()); Configuring a custom menu By default, Chrome custom tabs usually have a three-icon row with Forward, Page Info, and Refresh on top at all times and Find in page and Open in Browser (Open in Chrome can appear as well) at the footer of the menu. We, developers, have the ability to add and customize up to three menu items that will appear between the icon row and foot items as shown in the following screenshot: The menu we see is actually represented by an array of bundles, each with menu text and a pending intent that Chrome will call on your behalf when the user taps the item: //This part is adding custom buttons to the over flow menu String menuItemTitle = getString(R.string.menu_title_share); PendingIntent menuItemPendingIntent = createPendingShareIntent(); intentBuilder.addMenuItem(menuItemTitle, menuItemPendingIntent); String menuItemEmailTitle = getString(R.string.menu_title_email); PendingIntent menuItemPendingIntentTwo = createPendingEmailIntent(); intentBuilder.addMenuItem(menuItemEmailTitle, menuItemPendingIntentTwo); Configuring custom enter and exit animations Nothing is complete without a few animations to tag along. This is no different, as we have two transitions to make: one for the custom tab to enter and another for its exit; we have the option to set a specific animation for each start and exit animation: //Setting start and exit animation for the custom tab. intentBuilder.setStartAnimations(this,R.anim.slide_in_right, R.anim.slide_out_left); intentBuilder.setExitAnimations(this, android.R.anim.slide_in_left, android.R.anim.slide_out_right); Chrome warm-up Normally, after we finish setting up the intent with the intent builder, we should call CustomTabsIntent.launchUrl (Activity context, Uri url), which is a nonstatic method that will trigger a new custom tab activity to load the URL and show it in the custom tab. This can take up quite some time and impact the impression of smoothness the app provides. We all know that users demand a near-instantaneous experience, so Chrome has a service that we can connect to and ask it to warm up the browser and its native components. Calling this will ask Chrome to perform the following: The DNS preresolution of the URL's main domain The DNS preresolution of the most likely subresources Preconnection to the destination, including HTTPS/TLS negotiation The process to warm up Chrome is as follows: Connect to the service. Attach a navigation callback to get notified upon finishing the page load. On the service, call warmup to start Chrome behind the scenes. Create newSession; this session is used for all requests to the API. Tell Chrome which pages the user is likely to load with mayLaunchUrl. Launch the intent with the session ID generated in step 4. Connecting to the Chrome service Connecting to the Chrome service involves dealing with Android Interface Definition Language (AIDL). If you don't know about AIDL, read http://developer.android.com/guide/components/aidl.html. The interface is created with AIDL, and it automatically creates a proxy service class for you: CustomTabsClient.bindCustomTabsService() So, we check for the Chrome package name; in our sample project, we have a special method to check whether Chrome is present in all variations. After we set the package, we bind to the service and get a CustomTabsClient object that we can use until we're disconnected from the service: pkgName - This is one of several options checking to see if we have a version of Chrome installed can be one of the following static final String STABLE_PACKAGE = "com.android.chrome"; static final String BETA_PACKAGE = "com.chrome.beta"; static final String DEV_PACKAGE = "com.chrome.dev"; static final String LOCAL_PACKAGE = "com.google.android.apps.chrome"; private CustomTabsClient mClient; // Binds to the service. CustomTabsClient.bindCustomTabsService(myContext, pkgName, new CustomTabsServiceConnection() { @Override public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) { // CustomTabsClient should now be valid to use mClient = client; } @Override public void onServiceDisconnected(ComponentName name) { // CustomTabsClient is no longer valid which also invalidates sessions. mClient = null; } });  After we bind to the service, we can call the proper methods we need. Warming up the browser process The method for this is as follows: boolean CustomTabsClient.warmup(long flags) //With our valid client earlier we call the warmup method. mClient.warmup(0); Flags are currently not being used, so we pass 0 for now. The warm-up procedure loads native libraries and the browser process required to support custom tab browsing later on. This is asynchronous, and the return value indicates whether the request has been accepted or not. It returns true to indicate success. Creating a new tab session The method for this is as follows: boolean CustomTabsClient.newSession(ICustomTabsCallback callback) The new tab session is used as the grouping object tying the mayLaunchUrl call, the VIEW intent that we build, and the tab generated altogether. We can get a callback associated with the created session that would be passed for any consecutive mayLaunchUrl calls. This method returns CustomTabsSession when a session is created successfully; otherwise, it returns Null. Setting the prefetching URL The method for this is as follows: boolean CustomTabsSession.mayLaunchUrl (Uri url, Bundle extras, List<Bundle> otherLikelyBundles) This method will notify the browser that a navigation to this URL will happen soon. Make sure that you call warmup() prior to calling this method—this is a must. The most likely URL has to be specified first, and you can send an optional list of other likely URLs (otherLikelyBundles). Lists have to be sorted in a descending order and the optional list may be ignored. A new call to this method will lower the priority of previous calls and can result in URLs not being prefetched. Boolean values inform us whether the operation has been completed successfully. Custom tabs connection callback The method for this is as follows: void CustomTabsCallback.onNavigationEvent (int navigationEvent, Bundle extras) We have a callback triggered upon each navigation event in the custom tab. The int navigationEvent element is one of the six that defines the state the page is in. Refer to the following code for more information: //Sent when the tab has started loading a page. public static final int NAVIGATION_STARTED = 1; //Sent when the tab has finished loading a page. public static final int NAVIGATION_FINISHED = 2; //Sent when the tab couldn't finish loading due to a failure. public static final int NAVIGATION_FAILED = 3; //Sent when loading was aborted by a user action. public static final int NAVIGATION_ABORTED = 4; //Sent when the tab becomes visible. public static final int TAB_SHOWN = 5; //Sent when the tab becomes hidden. public static final int TAB_HIDDEN = 6; private static class NavigationCallback extends CustomTabsCallback { @Override public void onNavigationEvent(int navigationEvent, Bundle extras) { Log.i(TAG, "onNavigationEvent: Code = " + navigationEvent); } } Summary In this article, we learned about a newly added feature, Chrome custom tabs, which allows us to embed web content into our application and modify the UI. Chrome custom tabs allow us to provide a fuller, faster in-app web experience for our users. We use the Chrome engine under the hood, which allows faster loading than regular WebViews or loading the entire Chrome (or another browser) application. We saw that we can preload pages in the background, making it appear as if our data is blazing fast. We can customize the look and feel of our Chrome tab so that it matches our app. Among the changes we saw were the toolbar color, transition animations, and even the addition of custom actions to the toolbar. Custom tabs also benefit from Chrome features such as saved passwords, autofill, tap to search, and sync; these are all available within a custom tab. For developers, integration is quite easy and requires only a few extra lines of code in the basic level. The support library helps with more complex integration, if required. This is a Chrome feature, which means you get it on any Android device where the latest versions of Chrome are installed. Remember that the Chrome custom tab support library changes with new features and fixes, which is the same as other support libraries, so please update your version and make sure that you use the latest API to avoid any issues. To learn more about Chrome custom tabs and Android 6, refer to the following books: Android 6 Essentials (https://www.packtpub.com/application-development/android-6-essentials) Augmented Reality for Android Application Development (https://www.packtpub.com/application-development/augmented-reality-android-application-development) Resources for Article: Further resources on this subject: Android and iOS Apps Testing at a Glance [Article] Working with Xamarin.Android [Article] Mobile Phone Forensics – A First Step into Android Forensics [Article]
Read more
  • 0
  • 0
  • 5817
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-creating-and-managing-vmfs-datastores
Packt
05 Mar 2015
5 min read
Save for later

Creating and Managing VMFS Datastores

Packt
05 Mar 2015
5 min read
In this article by Abhilash G B, author of VMware vSphere 5.5 Cookbook, we will learn how to expand or grow a VMFS datastore with the help of two methods: using the Increase Datastore Capacity wizard and using the ESXi CLI tool vmkfstools. (For more resources related to this topic, see here.) Expanding/growing a VMFS datastore It is likely that you would run out of free space on a VMFS volume over time as you end up deploying more and more VMs on it, especially in a growing environment. Fortunately, accommodating additional free space on a VMFS volume is possible. However, this requires that the LUN either has free space left on it or it has been expanded/resized in the storage array. The procedure to resize/expand the LUN in the storage array differs from vendor to vendor, we assume that the LUN either has free space on it or has already been expanded. The following flowchart provides a high-level overview of the procedure: How to do it... We can expand a VMFS datastore using two methods: Using the Increase Datastore Capacity wizard Using the ESXi CLI tool vmkfstools Before attempting to grow the VMFS datastore, issue a rescan on the HBAs to ensure that the ESXi sees the increased size of the LUN. Also, make note of the NAA ID, LUN number, and the size of the LUN backing the VMFS datastore that you are trying to expand/grow. Using the Increase Datastore Capacity wizard We will go through the following process to expand an existing VMFS datastore using the vSphere Web Client's GUI. Use the vSphere Web Client to connect to vCenter Server. Navigate to Home | Storage. With the data center object selected, navigate to Related Objects | Datastores: Right-click on the datastore you intend to expand and click on Increase Datastore Capacity...:  Select the LUN backing the datastore and click on Next:  Use the Partition Configuration drop-down menu to select the free space left in DS01 to expand the datastore: On the Ready to Complete screen, review the information and click on Finish to expand the datastore: Using the ESXi CLI tool vmkfstools A VMFS volume can also be expanded using the vmkfstools tool. As with the use of any command-line tool, it can sometimes become difficult to remember the process if you are not doing it often enough to know it like the back of your hand. Hence, I have devised the following flowchart to provide an overview of the command-line steps that needs to be taken to expand a VMFS volume: Now that we know what the order of the steps would be from the flowchart, let's delve right into the procedure: Identify the datastore you want to expand using the following command, and make a note of the corresponding NAA ID: esxcli storage vmfs extent list Here, the NAA ID corresponding to the DS01 datastore is naa.6000eb30adde4c1b0000000000000083. Verify if the ESXi sees the new size of the LUN backing the datastore by issuing the following command: esxcli storage core device list -d naa.6000eb30adde4c1b0000000000000083 Get the current partition table information using the following command:Syntax: partedUtil getptbl "Devfs Path of the device" Command: partedUtil getptbl /vmfs/devices/disks/ naa.6000eb30adde4c1b0000000000000083 Calculate the new last sector value. Moving the last sector value closer to the total sector value is necessary in order to use additional space.The formula to calculate the last sector value is as follows: (Total number of sectors) – (Start sector value) = Last sector value So, the last sector value to be used is as follows: (31457280 – 2048) = 31455232 Resize the VMFS partition by issuing the following command:Syntax: partedUtil resize "Devfs Path" PartitionNumber NewStartingSector NewEndingSector Command: partedUtil resize /vmfs/devices/disks/ naa.6000eb30adde4c1b0000000000000083 1 2048 31455232 Issue the following command to grow the VMFS filesystem:Command syntax: vmkfstools –-growfs <Devfs Path: Partition Number> <Same Devfs Path: Partition Number> Command: vmkfstools --growfs /vmfs/devices/disks/ naa.6000eb30adde4c1b0000000000000083:1 /vmfs/devices/disks/ naa.6000eb30adde4c1b0000000000000083:1 Once the command is executed successfully, it will take you back to the root prompt. There is no on-screen output for this command. How it works... Expanding a VMFS datastore refers to the act of increasing its size within its own extent. This is possible only if there is free space available immediately after the extent. The maximum size of a LUN is 64 TB, so the maximum size of a VMFS volume is also 64 TB. The virtual machines hosted on this VMFS datastore can continue to be in the power-on state while this task is being accomplished. Summary This article walks you through the process of creating and managing VMFS datastores. Resources for Article: Further resources on this subject: Introduction Vsphere Distributed Switches? [article] Introduction Vmware Horizon Mirage [article] Backups Vmware View Infrastructure [article]
Read more
  • 0
  • 0
  • 5816

article-image-nodejs-fundamentals
Packt
22 May 2015
17 min read
Save for later

Node.js Fundamentals

Packt
22 May 2015
17 min read
This article is written by Krasimir Tsonev, the author of Node.js By Example. Node.js is one of the most popular JavaScript-driven technologies nowadays. It was created in 2009 by Ryan Dahl and since then, the framework has evolved into a well-developed ecosystem. Its package manager is full of useful modules and developers around the world have started using Node.js in their production environments. In this article, we will learn about the following: Node.js building blocks The main capabilities of the environment The package management of Node.js (For more resources related to this topic, see here.) Understanding the Node.js architecture Back in the days, Ryan was interested in developing network applications. He found out that most high performance servers followed similar concepts. Their architecture was similar to that of an event loop and they worked with nonblocking input/output operations. These operations would permit other processing activities to continue before an ongoing task could be finished. These characteristics are very important if we want to handle thousands of simultaneous requests. Most of the servers written in Java or C use multithreading. They process every request in a new thread. Ryan decided to try something different—a single-threaded architecture. In other words, all the requests that come to the server are processed by a single thread. This may sound like a nonscalable solution, but Node.js is definitely scalable. We just have to run different Node.js processes and use a load balancer that distributes the requests between them. Ryan needed something that is event-loop-based and which works fast. As he pointed out in one of his presentations, big companies such as Google, Apple, and Microsoft invest a lot of time in developing high performance JavaScript engines. They have become faster and faster every year. There, event-loop architecture is implemented. JavaScript has become really popular in recent years. The community and the hundreds of thousands of developers who are ready to contribute made Ryan think about using JavaScript. Here is a diagram of the Node.js architecture: In general, Node.js is made up of three things: V8 is Google's JavaScript engine that is used in the Chrome web browser (https://developers.google.com/v8/) A thread pool is the part that handles the file input/output operations. All the blocking system calls are executed here (http://software.schmorp.de/pkg/libeio.html) The event loop library (http://software.schmorp.de/pkg/libev.html) On top of these three blocks, we have several bindings that expose low-level interfaces. The rest of Node.js is written in JavaScript. Almost all the APIs that we see as built-in modules and which are present in the documentation, are written in JavaScript. Installing Node.js A fast and easy way to install Node.js is by visiting and downloading the appropriate installer for your operating system. For OS X and Windows users, the installer provides a nice, easy-to-use interface. For developers that use Linux as an operating system, Node.js is available in the APT package manager. The following commands will set up Node.js and Node Package Manager (NPM): sudo apt-get updatesudo apt-get install nodejssudo apt-get install npm Running Node.js server Node.js is a command-line tool. After installing it, the node command will be available on our terminal. The node command accepts several arguments, but the most important one is the file that contains our JavaScript. Let's create a file called server.js and put the following code inside: var http = require('http');http.createServer(function (req, res) {   res.writeHead(200, {'Content-Type': 'text/plain'});   res.end('Hello Worldn');}).listen(9000, '127.0.0.1');console.log('Server running at http://127.0.0.1:9000/'); If you run node ./server.js in your console, you will have the Node.js server running. It listens for incoming requests at localhost (127.0.0.1) on port 9000. The very first line of the preceding code requires the built-in http module. In Node.js, we have the require global function that provides the mechanism to use external modules. We will see how to define our own modules in a bit. After that, the scripts continue with the createServer and listen methods on the http module. In this case, the API of the module is designed in such a way that we can chain these two methods like in jQuery. The first one (createServer) accepts a function that is also known as a callback, which is called every time a new request comes to the server. The second one makes the server listen. The result that we will get in a browser is as follows: Defining and using modules JavaScript as a language does not have mechanisms to define real classes. In fact, everything in JavaScript is an object. We normally inherit properties and functions from one object to another. Thankfully, Node.js adopts the concepts defined by CommonJS—a project that specifies an ecosystem for JavaScript. We encapsulate logic in modules. Every module is defined in its own file. Let's illustrate how everything works with a simple example. Let's say that we have a module that represents this book and we save it in a file called book.js: // book.jsexports.name = 'Node.js by example';exports.read = function() {   console.log('I am reading ' + exports.name);} We defined a public property and a public function. Now, we will use require to access them: // script.jsvar book = require('./book.js');console.log('Name: ' + book.name);book.read(); We will now create another file named script.js. To test our code, we will run node ./script.js. The result in the terminal looks like this: Along with exports, we also have module.exports available. There is a difference between the two. Look at the following pseudocode. It illustrates how Node.js constructs our modules: var module = { exports: {} };var exports = module.exports;// our codereturn module.exports; So, in the end, module.exports is returned and this is what require produces. We should be careful because if at some point we apply a value directly to exports or module.exports, we may not receive what we need. Like at the end of the following snippet, we set a function as a value and that function is exposed to the outside world: exports.name = 'Node.js by example';exports.read = function() {   console.log('Iam reading ' + exports.name);}module.exports = function() { ... } In this case, we do not have an access to .name and .read. If we try to execute node ./script.js again, we will get the following output: To avoid such issues, we should stick to one of the two options—exports or module.exports—but make sure that we do not have both. We should also keep in mind that by default, require caches the object that is returned. So, if we need two different instances, we should export a function. Here is a version of the book class that provides API methods to rate the books and that do not work properly: // book.jsvar ratePoints = 0;exports.rate = function(points) {   ratePoints = points;}exports.getPoints = function() {   return ratePoints;} Let's create two instances and rate the books with different points value: // script.jsvar bookA = require('./book.js');var bookB = require('./book.js');bookA.rate(10);bookB.rate(20);console.log(bookA.getPoints(), bookB.getPoints()); The logical response should be 10 20, but we got 20 20. This is why it is a common practice to export a function that produces a different object every time: // book.jsmodule.exports = function() {   var ratePoints = 0;   return {     rate: function(points) {         ratePoints = points;     },     getPoints: function() {         return ratePoints;     }   }} Now, we should also have require('./book.js')() because require returns a function and not an object anymore. Managing and distributing packages Once we understand the idea of require and exports, we should start thinking about grouping our logic into building blocks. In the Node.js world, these blocks are called modules (or packages). One of the reasons behind the popularity of Node.js is its package management. Node.js normally comes with two executables—node and npm. NPM is a command-line tool that downloads and uploads Node.js packages. The official site, , acts as a central registry. When we create a package via the npm command, we store it there so that every other developer may use it. Creating a module Every module should live in its own directory, which also contains a metadata file called package.json. In this file, we have set at least two properties—name and version: {   "name": "my-awesome-nodejs-module",   "version": "0.0.1"} We can place whatever code we like in the same directory. Once we publish the module to the NPM registry and someone installs it, he/she will get the same files. For example, let's add an index.js file so that we have two files in the package: // index.jsconsole.log('Hello, this is my awesome Node.js module!'); Our module does only one thing—it displays a simple message to the console. Now, to upload the modules, we need to navigate to the directory containing the package.json file and execute npm publish. This is the result that we should see: We are ready. Now our little module is listed in the Node.js package manager's site and everyone is able to download it. Using modules In general, there are three ways to use the modules that are already created. All three ways involve the package manager: We may install a specific module manually. Let's say that we have a folder called project. We open the folder and run the following: npm install my-awesome-nodejs-module The manager automatically downloads the latest version of the module and puts it in a folder called node_modules. If we want to use it, we do not need to reference the exact path. By default, Node.js checks the node_modules folder before requiring something. So, just require('my-awesome-nodejs-module') will be enough. The installation of modules globally is a common practice, especially if we talk about command-line tools made with Node.js. It has become an easy-to-use technology to develop such tools. The little module that we created is not made as a command-line program, but we can still install it globally by running the following code: npm install my-awesome-nodejs-module -g Note the -g flag at the end. This is how we tell the manager that we want this module to be a global one. When the process finishes, we do not have a node_modules directory. The my-awesome-nodejs-module folder is stored in another place on our system. To be able to use it, we have to add another property to package.json, but we'll talk more about this in the next section. The resolving of dependencies is one of the key features of the package manager of Node.js. Every module can have as many dependencies as you want. These dependences are nothing but other Node.js modules that were uploaded to the registry. All we have to do is list the needed packages in the package.json file: {    "name": "another-module",    "version": "0.0.1",    "dependencies": {        "my-awesome-nodejs-module": "0.0.1"      } } Now we don't have to specify the module explicitly and we can simply execute npm install to install our dependencies. The manager reads the package.json file and saves our module again in the node_modules directory. It is good to use this technique because we may add several dependencies and install them at once. It also makes our module transferable and self-documented. There is no need to explain to other programmers what our module is made up of. Updating our module Let's transform our module into a command-line tool. Once we do this, users will have a my-awesome-nodejs-module command available in their terminals. There are two changes in the package.json file that we have to make: {   "name": "my-awesome-nodejs-module",   "version": "0.0.2",   "bin": "index.js"} A new bin property is added. It points to the entry point of our application. We have a really simple example and only one file—index.js. The other change that we have to make is to update the version property. In Node.js, the version of the module plays important role. If we look back, we will see that while describing dependencies in the package.json file, we pointed out the exact version. This ensures that in the future, we will get the same module with the same APIs. Every number from the version property means something. The package manager uses Semantic Versioning 2.0.0 (http://semver.org/). Its format is MAJOR.MINOR.PATCH. So, we as developers should increment the following: MAJOR number if we make incompatible API changes MINOR number if we add new functions/features in a backwards-compatible manner PATCH number if we have bug fixes Sometimes, we may see a version like 2.12.*. This means that the developer is interested in using the exact MAJOR and MINOR version, but he/she agrees that there may be bug fixes in the future. It's also possible to use values like >=1.2.7 to match any equal-or-greater version, for example, 1.2.7, 1.2.8, or 2.5.3. We updated our package.json file. The next step is to send the changes to the registry. This could be done again with npm publish in the directory that holds the JSON file. The result will be similar. We will see the new 0.0.2 version number on the screen: Just after this, we may run npm install my-awesome-nodejs-module -g and the new version of the module will be installed on our machine. The difference is that now we have the my-awesome-nodejs-module command available and if you run it, it displays the message written in the index.js file: Introducing built-in modules Node.js is considered a technology that you can use to write backend applications. As such, we need to perform various tasks. Thankfully, we have a bunch of helpful built-in modules at our disposal. Creating a server with the HTTP module We already used the HTTP module. It's perhaps the most important one for web development because it starts a server that listens on a particular port: var http = require('http');http.createServer(function (req, res) {   res.writeHead(200, {'Content-Type': 'text/plain'});   res.end('Hello Worldn');}).listen(9000, '127.0.0.1');console.log('Server running at http://127.0.0.1:9000/'); We have a createServer method that returns a new web server object. In most cases, we run the listen method. If needed, there is close, which stops the server from accepting new connections. The callback function that we pass always accepts the request (req) and response (res) objects. We can use the first one to retrieve information about incoming request, such as, GET or POST parameters. Reading and writing to files The module that is responsible for the read and write processes is called fs (it is derived from filesystem). Here is a simple example that illustrates how to write data to a file: var fs = require('fs');fs.writeFile('data.txt', 'Hello world!', function (err) {   if(err) { throw err; }   console.log('It is saved!');}); Most of the API functions have synchronous versions. The preceding script could be written with writeFileSync, as follows: fs.writeFileSync('data.txt', 'Hello world!'); However, the usage of the synchronous versions of the functions in this module blocks the event loop. This means that while operating with the filesystem, our JavaScript code is paused. Therefore, it is a best practice with Node to use asynchronous versions of methods wherever possible. The reading of the file is almost the same. We should use the readFile method in the following way: fs.readFile('data.txt', function(err, data) {   if (err) throw err;   console.log(data.toString());}); Working with events The observer design pattern is widely used in the world of JavaScript. This is where the objects in our system subscribe to the changes happening in other objects. Node.js has a built-in module to manage events. Here is a simple example: var events = require('events'); var eventEmitter = new events.EventEmitter(); var somethingHappen = function() {    console.log('Something happen!'); } eventEmitter .on('something-happen', somethingHappen) .emit('something-happen'); The eventEmitter object is the object that we subscribed to. We did this with the help of the on method. The emit function fires the event and the somethingHappen handler is executed. The events module provides the necessary functionality, but we need to use it in our own classes. Let's get the book idea from the previous section and make it work with events. Once someone rates the book, we will dispatch an event in the following manner: // book.js var util = require("util"); var events = require("events"); var Class = function() { }; util.inherits(Class, events.EventEmitter); Class.prototype.ratePoints = 0; Class.prototype.rate = function(points) {    ratePoints = points;    this.emit('rated'); }; Class.prototype.getPoints = function() {    return ratePoints; } module.exports = Class; We want to inherit the behavior of the EventEmitter object. The easiest way to achieve this in Node.js is by using the utility module (util) and its inherits method. The defined class could be used like this: var BookClass = require('./book.js'); var book = new BookClass(); book.on('rated', function() {    console.log('Rated with ' + book.getPoints()); }); book.rate(10); We again used the on method to subscribe to the rated event. The book class displays that message once we set the points. The terminal then shows the Rated with 10 text. Managing child processes There are some things that we can't do with Node.js. We need to use external programs for the same. The good news is that we can execute shell commands from within a Node.js script. For example, let's say that we want to list the files in the current directory. The file system APIs do provide methods for that, but it would be nice if we could get the output of the ls command: // exec.js var exec = require('child_process').exec; exec('ls -l', function(error, stdout, stderr) {    console.log('stdout: ' + stdout);    console.log('stderr: ' + stderr);    if (error !== null) {        console.log('exec error: ' + error);    } }); The module that we used is called child_process. Its exec method accepts the desired command as a string and a callback. The stdout item is the output of the command. If we want to process the errors (if any), we may use the error object or the stderr buffer data. The preceding code produces the following screenshot: Along with the exec method, we have spawn. It's a bit different and really interesting. Imagine that we have a command that not only does its job, but also outputs the result. For example, git push may take a few seconds and it may send messages to the console continuously. In such cases, spawn is a good variant because we get an access to a stream: var spawn = require('child_process').spawn; var command = spawn('git', ['push', 'origin', 'master']); command.stdout.on('data', function (data) {    console.log('stdout: ' + data); }); command.stderr.on('data', function (data) {    console.log('stderr: ' + data); }); command.on('close', function (code) {    console.log('child process exited with code ' + code); }); Here, stdout and stderr are streams. They dispatch events and if we subscribe to these events, we will get the exact output of the command as it was produced. In the preceding example, we run git push origin master and sent the full command responses to the console. Summary Node.js is used by many companies nowadays. This proves that it is mature enough to work in a production environment. In this article, we saw what the fundamentals of this technology are. We covered some of the commonly used cases. Resources for Article: Further resources on this subject: AngularJS Project [article] Exploring streams [article] Getting Started with NW.js [article]
Read more
  • 0
  • 0
  • 5816

article-image-building-android-must-know
Packt
13 Sep 2013
14 min read
Save for later

Building Android (Must know)

Packt
13 Sep 2013
14 min read
(For more resources related to this topic, see here.) Getting ready You need Ubuntu 10.04 LTS or later (Mac OS X is also supported by the build system, but we will be using Ubuntu for this article). This is the supported build operating system, and the one for which you will get the most help from the online community. In my examples, I use Ubuntu 11.04, which is also reasonably well supported. You need approximately 6 GB of free space for the Android code files. For a complete build, you need 25 GB of free space. If you are using Linux in a virtual machine, make sure the RAM or the swap size is at least 16 GB, and you have 30 GB of disk space to complete the build. As of Android Versions 2.3 (Gingerbread) and later, building the system is only possible on 64-bit computers. Using 32-bit machines is still possible if you work with Froyo (Android 2.2). However, you can still build later versions on a 32-bit computer using a few "hacks" on the build scripts that I will describe later. The following steps outline the process needed to set up a build environment and compile the Android framework and kernel: Setting up a build environment Downloading the Android framework sources Building the Android framework Building a custom kernel In general, your (Ubuntu Linux) build computer needs the following: Git 1.7 or newer (GIT is a source code management tool), JDK 6 to build Gingerbread and later versions, or JDK 5 to build Froyo and older versions Python 2.5 – 2.7 GNU Make 3.81 – 3.82 How to do it... We will first set up the build environment with the help of the following steps: All of the following steps are targeted towards 64-bit Ubuntu. Install the required JDK by executing the following command: JDK6sudo add-apt-repository "deb http: //archive.canonical.com/ lucid partner" sudo apt-get update sudo apt-get install sun-java6-jdkJDK5sudo add-apt-repository "deb http: //archive.ubuntu.com/ubuntu hardy main multiverse" sudo add-apt-repository "deb http: //archive.ubuntu.com/ubuntu hardy-updates main multiverse" sudo apt-get update sudo apt-get install sun-java5-jdk Install the required library dependencies: sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev libc6-dev lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev libgl1-mesa-dev g++-multilib mingw32 tofrodos python-markdown libxml2-utils xsltproc [OPTIONAL]. On Ubuntu 10.10, a symlink is not created between libGL.so.1 and libGL.so, which sometimes causes the build process to fail: sudo ln -s /usr/lib32/mesa/libGL.so.1 /usr/lib32/mesa/libGL.so [OPTIONAL] On Ubuntu 11.10, an extra dependency is sudo apt-get install libx11-dev:i386 Now, we will download the Android sources from Google's repository. Install repo. Make sure you have a /bin directory and that it exists in your PATH variable: mkdir ~/bin PATH=~/bin:$PATH curl https: //dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo chmod a+x ~/bin/repo Repo is a python script used to download the Android sources, among other tasks. It is designed to work on top of GIT. Initialize repo. In this step, you need to decide the branch of the Android source you wish to download. If you wish to make use of Gerrit, which is the source code reviewing tool used, make sure you have a live Google mail address. You will be prompted to use this e-mail address when repo initializes. Create a working directory on your local machine. We will call this mkdir android_srccd android_src The following command will initialize repo to download the "master" branch: repo init -u https://android.googlesource.com/platform/manifest The following command will initialize repo to download the Gingerbread 2.3.4 branch: repo init -u https: //android.googlesource.com/platform/manifest -b android-2.3.4_r1 The -b switch is used to specify the branch you wish to download. Once repo is configured, we are ready to obtain the source files. The format of the command is as follows: repo sync -jX -jX is optional, and is used for parallel fetch. The following command will sync all the necessary source files for the Android framework. Note that these steps are only to download the Android framework files.Kernel download is a separate process. repo sync -j16 The source code access is anonymous, that is, you do not need to be registered with Google to be able to download the source code. The servers allocate a fixed quota to each IP address that accesses the source code. This is to protect the servers against excessive download traffic. If you happen to be behind a NAT and share an IP address with others, who also wish to download the code, you may encounter error messages from the source code servers warning about excessive usage. In this case, you can solve the problem with authenticated access. In this method, you get a separate quota based on your user ID, generated by the password generator system. The password generator and associated instructions are available at https://android.googlesource.com/new-password. Once you have obtained a user ID/password and set up your system appropriately, you can force authentication by using the following command: repo init -u https://android.googlesource.com/a/platform/manifest Notice the /a/ in the URI. This indicates authenticated access. Proxy issues If you are downloading from behind a proxy, set the following environment variables: export HTTP_PROXY=http://<proxy_user_id>:<proxy_password>@<proxy_server>:<proxy_port>export HTTPS_PROXY=http://<proxy_user_id>:<proxy_password>@<proxy_server>:<proxy_port> Next, we describe the steps needed to build the Android framework sources: Initialize the terminal environment. Certain build-time tools need to be included in your current terminal environment. So, navigate to your source directory: cd android_src/source build/envsetup.sh The sources can be built for various targets. Each target descriptor has the BUILD-BUILDTYPE format: BUILD: Refers to a specific combination of the source code for a certain device. For example, full_maguro targets Galaxy Nexus or generic targets the emulator. BUILDTYPE: This can be one of the following three values: user: Suitable for production builds userdebug: Similar to user, with with root access in ADB for easier debugging eng: Development build only We will be building for the emulator in our current example. Issue the following command to do so: lunch full-eng To actually build the code, we will use make. The format is as follows: make -jX Where X indicates the number of parallel builds. The usual rule is: X is the number of CPU cores + 2. This is an experimental formula, and the reader should feel free to test it with different values. To build the code: make -j6 Now, we must wait till the build is complete. Depending on your system's specifications, this can take anywhere between 20 minutes and 1 hour. At the end of a successful build, the output looks similar to the following (note that this may vary depending on your target): ...target Dex: SystemUI Copying: out/target/common/obj/APPS/SystemUI_intermediates/noproguard.classes.dex target Package: SystemUI (out/target/product/generic/obj/APPS/SystemUI_intermediates/package.apk) 'out/target/common/obj/APPS/SystemUI_intermediates//classes.dex' as 'classes.dex'... Install: out/target/product/generic/system/app/SystemUI.apk Finding NOTICE files: out/target/product/generic/obj/NOTICE_FILES/hash-timestamp Combining NOTICE files: out/target/product/generic/obj/NOTICE.html Target system fs image: out/target/product/generic/obj/PACKAGING/systemimage_intermediates/system.img Install system fs image: out/target/product/generic/system.img Installed file list: out/target/product/generic/installed-files.txt DroidDoc took 440 sec. to write docs to out/target/common/docs/doc-comment-check A better check for a successful build is to examine the newly created files inside the following directory. The build produces a few main files inside android_src/out/target/product/<DEVICE>/, which are as follows: system.img: The system image file boot.img: Contains the kernel recovery.img: Contains code for recovery partition of the device In the case of an emulator build, the preceding files will appear at android_src/out/target/product/generic/. Now, we can test our build simply by issuing the emulator command: emulator This launches an Android emulator, as shown in the following screenshot, running the code we've just built: The code we've downloaded contains prebuilt Linux kernels for each supported target. If you only wish to change the framework files, you can use the prebuilt kernels, which are automatically included in the build images. If you are making specific changes to the kernel, you will have to obtain a specific kernel and build it separately (shown here), which is explained later: Faster Builds – CCACHE The framework code contains C language and Java code. The majority of the C language code exists as shared objects that are built during the build process. If you issue the make clean command, which deletes all the built code (simply deleting the build output directory has the same effect as well) and then rebuild, it will take a significant amount of time. If no changes were made to these shared libraries, the build time can be sped up with CCACHE, which is a compiler cache. In the root of the source directory android_src/, use the following command: export USE_CCACHE=1export CCACHE_DIR=<PATH_TO_YOUR_CCACHE_DIR> To set a cache size: prebuilt/linux-x86/ccache/ccache -M 50G This reserves a cache size of 50 GB. To watch how the cache is used during the build process, use the following command (navigate to your source directory in another terminal): watch -n1 -d prebuilt/linux-x86/ccache/ccache -s In this part, we will obtain the sources and build the goldfish emulator kernel. Building kernels for devices is done in a similar way. goldfish is the name of the kernel modified for the Android QEMU-based emulator. Get the kernel sources: Create a subdirectory of android_src: mkdir kernel_codecd kernel_codegit clone https: //android.googlesource.com/kernel/goldfish.gitgit branch -r This will clone goldfish.git into a folder named goldfish (created automatically) and then list the remote branches available. The output should look like the following (this is seen after the execution of the git branch): origin/HEAD -> origin/master origin/android-goldfish-2.6.29 origin/linux-goldfish-3.0-wip origin/master Here, in the following command, we notice origin/android-goldfish-2.6.29, which is the kernel we wish to obtain: cd goldfishgit checkout --track -b android-goldfish-2.6.29 origin/android-goldfish-2.6.29 This will obtain the kernel code: Set up the build environment. We need to initialize the terminal environment by updating the system PATH variable to point to a cross compiler which will be used to compile the Linux kernel. This cross compiler is already available as a prebuilt binary distributed with the Android framework sources: export PATH=<PATH_TO_YOUR_ANDROID_SRC_DIR>/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin:$PATH Run an emulator (you may choose to run the emulator with the system image that we just built earlier. We need this to obtain the kernel configuration file. Instead of manually configuring it, we choose to pull the config file of a running kernel. Make sure ADB is still in your path. It will be in your PATH variable if you haven't closed the terminal window since building the framework code, otherwise execute the following steps sequentially. (Note that you have to change directory to ANDROID_SRC to execute the following command). source build/envsetup.shlunch full_engadb pull /proc/config.gzgunzip config.gz cp config .config The preceding command will copy the config file of the running kernel into our kernel build tree. Start the compilation process: export ARCH=armexport SUBARCH=arm make If the following comes up: Misc devices (MISC_DEVICES) [Y/n/?] y Android pmem allocator (ANDROID_PMEM) [Y/n] y Enclosure Services (ENCLOSURE_SERVICES) [N/y/?] n Kernel Debugger Core (KERNEL_DEBUGGER_CORE) [N/y/?] n UID based statistics tracking exported to /proc/uid_stat (UID_STAT) [N/y] n Virtual Device for QEMU tracing (QEMU_TRACE) [Y/n/?] y Virtual Device for QEMU pipes (QEMU_PIPE) [N/y/?] (NEW) Enter y as the answer. This is some additional Android-specific configuration needed for the build. Now we have to wait till the build is complete. The final lines of the build output should look like the following (note that this can change depending on your target): ... LD vmlinux SYSMAP System.map SYSMAP .tmp_System.map OBJCOPY arch/arm/boot/Image Kernel: arch/arm/boot/Image is ready AS arch/arm/boot/compressed/head.o GZIP arch/arm/boot/compressed/piggy.gz AS arch/arm/boot/compressed/piggy.o CC arch/arm/boot/compressed/misc.o LD arch/arm/boot/compressed/vmlinux OBJCOPY arch/arm/boot/zImage Kernel: arch/arm/boot/zImage is ready As the last line states, the new zImage is available inside arch/arm/ boot/. To test it, we boot the emulator with this newly built image. Copy zImage to an appropriate directory. I just copied it to android_src/: emulator -kernel zImage To verify that the emulator is indeed running our kernel, use the following command: adb shell # cat /proc/version The output will look like: Linux version 2.6.29-gef9c64a (earlence@earlence-Satellite-L650) (gcc version 4.4.3 (GCC) ) #1 Mon Jun 4 16:35:00 CEST 2012 This is our custom kernel, since we observe the custom build string (earlence@earlence-Satellite-L650) present as well as the time of the compilation. The build string will be the name of your computer. Once the emulator has booted up, you will see a window similar to the following: Following are the steps required to build the framework on a 32-bit system: Make the following simple changes to build Gingerbread on 32-bit Ubuntu. Note that these steps assume that you have set up the system for a Froyo build. Assuming a Froyo build computer setup, the following steps guide you on incrementally making changes such that Gingerbread and later builds are possible. To set up for Froyo, please follow the steps explained at http://source.android.com/source/initializing.html. In build/core/main.mk, change ifneq (64,$(findstring 64,$(build_arch))) to ifneq (i686,$(findstring i686,$(build_arch))). Note that there are two changes on that line. In the following files: external/clearsilver/cgi/Android.mk external/clearsilver/java-jni/Android.mk external/clearsilver/util/Android.mk external/clearsilver/cs/Android.mk change:LOCAL_CFLAGS += -m64 LOCAL_LDFLAGS += -m64 to:LOCAL_CFLAGS += -m32 LOCAL_LDFLAGS += -m32 Install the following packages (in addition to the packages you must have installed for the Froyo build): sudo apt-get install lib64z1-dev libc6-dev-amd64 g++-multilib lib64stdc++6 Install Java 1.6 using the following command: sudo apt-get install sun-java6-jdk Summary The Android build system is a combination of several standard tools and custom wrappers. Repo is one such wrapper script that takes care of GIT operations and makes it easier for us to work with the Android sources. The kernel trees are maintained separately from the framework source trees. Hence, if you need to make customizations to a particular kernel, you will have to download and build it separately. The keen reader may be wondering how we are able to run the emulator if we never built a kernel in when we just compiled the framework. Android framework sources include prebuilt binaries for certain targets. These binaries are located in the /prebuilt directory under the framework source root directory. The kernel build process is more or less the same as building kernels for desktop systems. There are only a few Android-specific compilation switches, which we have shown to be easily configurable given an existing configuration file for the intended target. The sources consist of C/C++ and Java code. The framework does not include the kernel sources, as these are maintained in a separate GIT tree. In the next recipe, we will explain the framework code organization. It is important to understand how and where to make changes while developing custom builds. Resources for Article: Further resources on this subject: Android Native Application API [Article] Animating Properties and Tweening Pages in Android 3-0 [Article] So, what is Spring for Android? [Article]  
Read more
  • 0
  • 0
  • 5814

article-image-exchange-server-2010-windows-powershell-working-distribution-groups
Packt
27 Jul 2011
8 min read
Save for later

Exchange Server 2010 Windows PowerShell: Working with Distribution Groups

Packt
27 Jul 2011
8 min read
Microsoft Exchange 2010 PowerShell Cookbook Manage and maintain your Microsoft Exchange 2010 environment with the Exchange Management Shell and Windows PowerShell 2.0 using this book and eBook Performing some basic steps To work with the code samples in this article, follow these steps to launch the Exchange Management Shell: Log onto a workstation or server with the Exchange Management Tools installed Open the Exchange Management Shell by clicking on Start | All Programs | Exchange Server 2010 Click on the Exchange Management Shell shortcut Reporting on distribution group membership One of the common requests you are likely to receive as an Exchange administrator is to generate a report detailing which recipients are members of one or more distribution groups. In this recipe, we'll take a look at how to retrieve this information from the Exchange Management Shell. How to do it... To view a list of each distribution group member interactively, use the following code: foreach($i in Get-DistributionGroup -ResultSize Unlimited) { Get-DistributionGroupMember $i -ResultSize Unlimited | Select-Object @{n="Member";e={$_.Name}}, RecipientType, @{n="Group";e={$i.Name}} } This will generate a list of Exchange recipients and their associated distribution group membership. How it works... This code loops through each item returned from the Get-DistributionGroup cmdlet. As we process each group, we run the Get-DistributionGroupMember cmdlet to determine the member list for each group and then use Select-Object to construct a custom object that provides Member, RecipientType, and Group properties. Notice that, when running both Exchange cmdlets, we're setting the -ResultSize parameter to Unlimited to ensure that the details will be retrieved in the event that there are more than 1,000 groups or group members. There's more... The previous code sample will allow you to view the output in the shell. If you want to export this information to a CSV file, use the following code: $report=foreach($i in Get-DistributionGroup -ResultSize Unlimited) { Get-DistributionGroupMember $i -ResultSize Unlimited | Select-Object @{n="Member";e={$_.Name}}, RecipientType, @{n="Group";e={$i.Name}} } The difference this time is that the output from our code is being saved in the $report variable. Once the report has been generated, the $report object is then exported to a CSV file that can be opened in Excel. Adding members to a distribution group from an external file When working in large or complex environments, performing bulk operations is the key to efficiency. Using PowerShell core cmdlets such as Get-Content and Import-CSV, we can easily import external data into the shell and use this information to perform bulk operations on hundreds or thousands of objects in a matter of seconds. Obviously, this can vastly speed up the time we spend on routine tasks and greatly increase our efficiency. In this recipe, we'll use these concepts to add members to distribution groups in bulk from a text or CSV file using the Exchange Management Shell. How to do it... Create a text file called c:users.txt that lists the recipients in your organization that you want to add to a group. Make sure you enter them one line at a time, as shown in the following screen shot: Next, execute the following code to add the list of recipients to a distribution group: Get-Content c:users.txt | ForEach-Object { Add-DistributionGroupMember -Identity Sales -Member $_ } When the code runs, each user listed in the c:users.txt file will be added to the Sales distribution group. How it works... When importing data from a plain text file, we use the Get-Content cmdlet, which will read the content of the file into the shell one line at a time. In this example, we pipe the content of the file to the ForEach-Object cmdlet, and as each line is processed we execute the Add-DistributionGroupMember. Inside the For-EachObject script block we use the Add-DistributionGroupMember cmdlet and assign the $_ object, which is the current recipient item in the pipeline, to the -Member parameter. To remove recipients from a distribution group, you can use the Remove-DistributionGroupMember cmdlet. Keep in mind that this text file does not have to contain the SMTP address of the recipient. You can also use the Active Directory account name, User Principal Name, Distinguished Name, GUID, or LegacyExchangeDN values. The important thing is that the file contains a valid and unique value for each recipient. If the identity of the recipient cannot be determined, the Add-DistributionGroupMember command will fail. There's more... In addition to using plain text files, we can also import recipients from a CSV file and add them to a distribution group. Let's say that you have a CSV file setup with multiple columns, such as FirstName, LastName, and EmailAddress. When you import the CSV file, the data can be accessed using the column headers as the property names for each object. Take a look at the following screenshot: Here you can see that each item in this collection has an EmailAddress property. As long as this information corresponds to the recipient data in the Exchange organization, we can simply loop through each record in the CSV file and add these recipients to a distribution group: Import-Csv C:users.csv | ForEach-Object { Add-DistributionGroupMember Sales -Member $_.EmailAddress } The given code uses the Import-CSV cmdlet to loop through each item in the collection. As we process each record, we add the recipient to the Sales distribution group using the $_.EmailAddress object. Previewing dynamic distribution group membership The concept of the dynamic distribution group was introduced with the initial release of Exchange 2007 and included a new way to create and manage distribution groups. Unlike regular distribution groups whose members are statically defined, a dynamic distribution group determines its members based on a recipient filter. These recipient filters can be very complex, or they can be based on simple conditions, such as including all the users with a common value set for their Company or Department attributes in Active Directory. Since these dynamic groups are based on a query, they do not actually contain group members and if you want to preview the results of the groups query in the shell you need to use a series of commands. In this recipe, we'll take a look at how to view the membership of dynamic distribution groups in the Exchange Management Shell. How to do it... Imagine that we have a dynamic distribution group named Legal that includes all of the users in Active Directory with a Department attribute set to the word Legal. We can use the following commands to retrieve the current list of recipients for this group: $legal= Get-DynamicDistributionGroup -Identity legal Get-Recipient -RecipientPreviewFilter $legal.RecipientFilter How it works... Recipient filters for dynamic distribution groups use OPATH filters that are accessible through the RecipientFilter property of a dynamic distribution group object. As you can see here, we have specified the Legal groups OPATH filter when running the Get-Recipient cmdlet with the –RecipientPreviewFilter parameter. Conceptually, this would be similar to running the following command: Get-Recipient -RecipientPreviewFilter "Department -eq 'Legal'" Technically, there is a little bit more to it than that. If we were to actually look at the value for the RecipientFilter property of this dynamic distribution group, we would see much more information in addition to the filter defined for the Legal department. This is because Exchange automatically adds several additional filters when it creates a dynamic distribution group that excludes system mailboxes, discovery mailboxes, arbitration mailboxes, and more. This ends up being quite a bit of information, and creating an object instance of the dynamic distribution group gives us easy access to the existing OPATH filter that can be previewed with the Get-Recipient cmdlet. There's more... When working with regular distribution groups, you may notice that there is a cmdlet called Get-DistributionGroupMember. This allows you to retrieve a list of every user that is a member of a distribution group. Unfortunately, there is no equivalent cmdlet for dynamic distribution groups, and we need to use the method outlined previously that uses the Get-Recipient cmdlet to determine the list of recipients in a dynamic distribution group. If you find yourself doing this frequently, it probably makes sense to wrap these commands up into a function that can be added to your PowerShell profile. This will allow you to determine the members of dynamic distribution group using a single command that will be available to you every time you start the shell. Here is the code for a function called Get-DynamicDistributionGroupMember, which can be used to determine the list of recipients included in a dynamic distribution group: function Get-DynamicDistributionGroupMember { param( [Parameter(Mandatory=$true)] $Identity ) $group = Get-DynamicDistributionGroup -Identity $Identity Get-Recipient -RecipientPreviewFilter $group.RecipientFilter } Once this function is loaded into your shell session, you can run it just like a cmdlet: You can see that the command returns the recipients that match the OPATH filter for the Legal distribution group and is much easier to type than the original example.
Read more
  • 0
  • 0
  • 5813
article-image-my-first-puppet-module
Packt
07 Sep 2015
15 min read
Save for later

My First Puppet Module

Packt
07 Sep 2015
15 min read
In this article by Jussi Heinonen, the author of Learning Puppet, we will get started with creating a Puppet module and the various aspects associated with it. Together with all the manifest files that we created so far, there are several of them already, and we haven't yet started to develop Puppet manifests. As the number of manifests expand, one may start wondering how files can be distributed and applied efficiently across multiple systems. This article will introduce you to Puppet modules and show you how to prepare a simple web server environment with Puppet. (For more resources related to this topic, see here.) Introducing the Puppet module The Puppet module is a collection of code and data that usually solves a particular problem, such as the installation and configuration of a web server. A module is packaged and distributed in the TAR (tape archive) format. When a module is installed, Puppet extracts the archive file on the disk, and the output of the installation process is a module directory that contains Puppet manifests (code), static files (data), and template files (code and data). Static files are typically some kind of configuration files that we want to distribute across all the nodes in the cluster. For example, if we want to ensure that all the nodes in the cluster are using the same DNS server configuration, we can include the /etc/resolv.conf file in the module and tell Puppet to apply it across all the nodes. This is just an example of how static files are used in Puppet and not a recommendation for how to configure DNS servers. Like static files, template files can also be used to provide configuration. The difference between a static and template file is that a static file will always have the same static content when applied across multiple nodes, whereas the template file can be customized based on the unique characteristics of a node. A good example of a unique characteristic is an IP address. Each node (or a host) in the network must have a unique IP address. Using the template file, we can easily customize the configuration on every node, wherever the template is applied. It's a good practice to keep the manifest files short and clean to make them easy to read and quick to debug. When I write manifests, I aim to keep the length of the manifest file in less than a hundred lines. If the manifest length exceeds 100 lines, then this means that I may have over-engineered the process a little bit. If I can't simplify the manifest to reduce the number of lines, then I have to split the manifest into multiple smaller manifest files and store these files within a Puppet module. The Puppet module structure The easiest way to get familiar with a module structure is to create an empty module with the puppet module generate command. As we are in the process of building a web server that runs a web application, we should give our module a meaningful name, such as learning-webapp. The Puppet module name format Before we create our first module, let's take a quick look at the Puppet module naming convention. The Puppet module name is typically in the format of <author>-<modulename>. A module name must contain one hyphen character (no more, no less) that separates the <author> and the <modulename> names. In the case of our learning-webapp module that we will soon create, the author is called learning and the module name is webapp, thus the module name learning-webapp. Generating a Puppet module Let's take a look at the following steps to create the learning-webapp Puppet module: Start the puppet-agent virtual machine. Using the cd command, navigate to the directory that is shared via the shared folder. On my virtual machine, my shared folder appears as /media/sf_learning, and I can move to the directory by running the following command: # cd /media/sf_learning Then, I'll create an empty puppet module with the command puppet module generate learning-webapp --skip-interview and the command returns a list of files and directories that the module contains: # puppet module generate learning-webapp --skip-interview Notice: Generating module at /media/sf_learning/learning-webapp Notice: Populating templates... Finished; module generated in learning-webapp. learning-webapp/metadata.json learning-webapp/Rakefile learning-webapp/manifests learning-webapp/manifests/init.pp learning-webapp/spec learning-webapp/spec/spec_helper.rb learning-webapp/spec/classes learning-webapp/spec/classes/init_spec.rb learning-webapp/Gemfile learning-webapp/tests learning-webapp/tests/init.pp learning-webapp/README.md To get a better view of how the files in the directories are organized in the learning-webapp module, you can run the tree learning-webapp command, and this command will produce the following tree structure of the files:   Here, we have a very simple Puppet module structure. Let's take a look at the files and directories inside the module in more detail: Gemfile: A file used for describing the Ruby package dependencies that are used for unit testing. For more information on Gemfile, visit http://bundler.io/v1.3/man/gemfile.5.html. manifests: A directory for all the Puppet manifest files in the module. manifests/init.pp: A default manifest file that declares the main Puppet class called webapp. metadata.json: A file that contains the module metadata, such as the name, version, and module dependencies. README.md: A file that contains information about the usage of the module. Spec: An optional directory for automated tests. Tests: A directory that contains examples that show how to call classes that are stored in the manifests directory. tests/init.pp: A file containing an example how to call the main class webapp in file manifests/init.pp. A Puppet class A Puppet class is a container for Puppet resources. A class typically includes references to multiple different types of resources and can also reference other Puppet classes. The syntax for declaring a Puppet class is not that different from declaring Puppet resources. A class definition begins with the keyword class, followed by the name of the class (unquoted) and an opening curly brace ({). A class definition ends with a closing curly brace (}). Here is a generic syntax of the Puppet class: class classname { } Let's take a look at the manifests/init.pp file that you just created with the puppet module generate command. Inside the file, you will find an empty Puppet class called webapp. You can view the contents of the manifests/init.pp file using the following command: # cat /media/sf_learning/learning-webapp/manifests/init.pp The init.pp file mostly contains the comment lines, which are prefixed with the # sign, and these lines can be ignored. At the end of the file, you can find the following declaration for the webapp class: class webapp { } The webapp class is a Puppet class that does nothing as it has no resources declared inside it. Resources inside the Puppet class Let's add a notify resource to the webapp class in the manifests/init.pp file before we go ahead and apply the class. The notify resource does not manage any operating system resources, such as files or users, but instead, it allows Puppet to report a message when a resource is processed. As the webapp module was created inside shared folders, you no longer have to use the Nano editor inside the virtual machine to edit manifests. Instead, you can use a graphical text editor, such as a Notepad on Windows or Gedit on the Linux host. This should make the process of editing manifests a bit easier and more user friendly. The directory that I shared on the host computer is /home/jussi/learning. When I take a look inside this directory, I can find a subdirectory called learning-webapp, which is the Puppet module directory that we created a moment ago. Inside this, there is a directory called manifests, which contains the init.pp file. Open the init.pp file in the text editor on the host computer and scroll down the file until you find the webapp class code block that looks like the following: class webapp { } If you prefer to carry on using the Nano editor to edit manifest files (I salute you!), you can open the init.pp file inside the virtual machine with the nano /media/sf_learning/learning-webapp/manifests/init.pp command. The notify resource that we are adding must be added inside the curly braces that begins and ends the class statement; otherwise, the resource will not be processed when we apply the class. Now we can add a simple notify resource that makes the webapp class look like the following when completed: class webapp { notify { 'Applying class webapp': } } Let's take a look at the preceding lines one by one: Line 1 begins with the webapp class, followed by the opening curly brace. Line 2 declares a notify resource and a new opening curly brace, followed by the resource name. The name of the notify resource will become the message that Puppet prints on the screen when the resource from a class is processed. Line 3 closes the notify resource statement. Line 4 indicates that the webapp class finishes here. Once you have added the notify resource to the webapp class, save the init.pp file. Rename the module directory Before we can apply our webapp class, we must rename our module directory. It is unclear to me as to why the puppet module generate command creates a directory name that contains a hyphen character (as in learning-webapp). The hyphen character is not allowed to be present in the Puppet module directory name. For this reason, we must rename the learning-webapp directory before we can apply the webapp class inside it. As the learning-webapp module directory lives in the shared folders, you can either use your preferred file manager program to rename the directory, or you can run the following two commands inside the Puppet Learning VM to change the directory name from learning-webapp to webapp: # cd /media/sf_learning # mv learning-webapp webapp Your module directory name should now be webapp, and we can move on to apply the webapp class inside the module and see what happens. Applying a Puppet class You can try running the puppet apply webapp/manifests/init.pp command but don't be disappointed when nothing happens. Why is that? The reason is because there is nothing inside the init.pp file that references the webapp class. If you are familiar with object-oriented programming, you may know that a class must be instantiated in order to get services from it. In this case, Puppet behaves in a similar way to object-oriented programming languages, as you must make a reference to the class in order to tell Puppet to process the class. Puppet has an include keyword that is used to reference a class. The include keyword in Puppet is only available for class resources, and it cannot be used in conjunction with any other type of Puppet resources. To apply the webapp class, we can make use of the init.pp file under the tests directory that was created when the module was generated. If you take a look inside the tests/init.pp file, you will find a line include webapp. The tests/init.pp file is the one that we should use to apply the webapp class. Here are the steps on how to apply the webapp class inside the Puppet Learning VM: Go to the parent directory of the webapp module: # cd /media/sf_learning Apply the webapp class that is included in the tests/init.pp file: # puppet apply --modulepath=./ webapp/tests/init.pp When the class is applied successfully, you should see the notify resource that was added to the webapp class that appears on lines 2 and 3 in the following Puppet report: Notice: Compiled catalog for web.development.vm in environment production in 0.05 seconds Notice: Applying class webapp Notice: /Stage[main]/Webapp/Notify[Applying class webapp]/message: defined 'message' as 'Applying class webapp' Notice: Finished catalog run in 0.81 seconds Let's take a step back and look again at the command that we used to apply to the webapp class: # puppet apply --modulepath=./ webapp/tests/init.pp The command can be broken down into three elements: puppet apply: The puppet apply command is used when applying a manifest from the command line. modulepath=./: This option is used to tell Puppet what filesystem path to use to look for the webapp module. The ./ (dot forward slash) notation means that we want our current /media/sf_learning working directory to be used as the modulepath value. webapp/tests/init.pp: This is the file that the puppet apply command should read. Installing a module from Puppet Forge Puppet Forge is a public Puppet module repository (https://forge.puppetlabs.com) for modules that are created by the community around Puppet. Making use of the modules in Puppet Forge is a great way to build a software stack quickly, without having to write all the manifests yourself from scratch. The web server that we are going to install is a highly popular Apache HTTP Server (http://httpd.apache.org/), and there is a module in Puppet Forge called puppetlabs-apache that we can install. The Puppetlabs-apache module provides all the necessary Puppet resources for the Apache HTTP Server installation. Note that the puppet module installation requires an Internet connection. To test whether the Puppet Learning VM can connect to the Internet, run the following command on the command line: # host www.google.com On successful completion, the command will return the following output: www.google.com has address 216.58.211.164www.google.com has IPv6 address 2a00:1450:400b:801::2004 Note that the reported IP address may vary. As long as the host command returns www.google.com has address …, the Internet connection works. Now that the Internet connection has been tested, you can now proceed with the module installation. Before we install the puppetlabs-apache module, let's do a quick search to confirm that the module is available in Puppet Forge. The following command will search for the puppetlabs-apache module: # puppet module search puppetlabs-apache When the search is successful, it returns the following results:   Then, we can install the module. Follow these steps to install the puppetlabs-apache module: In the Puppet Learning VM, go to the shared folders /media/sf_learning directory by running the cd /media/sf_learning command. Then, run the following command: # puppet module install --modulepath=./ puppetlabs-apache The --modulepath=./ option specifies that the module should be installed in the current /media/sf_learning working directory The installation will take a couple of minutes to complete, and once it is complete, you will see the following lines appear on the screen: Notice: Preparing to install into /media/sf_learning ... Notice: Preparing to install into /media/sf_learning ... Notice: Downloading from https://forgeapi.puppetlabs.com ... Notice: Installing -- do not interrupt ... /media/sf_learning └─┬ puppetlabs-apache (v1.2.0) ├── puppetlabs-concat (v1.1.2) └── puppetlabs-stdlib (v4.8.0) Let's take a look at the output line by line to fully understand what happened during the installation process: Line 1 tells us that the module is going to be installed in the /media/sf_learning directory, which is our current working directory. This directory was specified with the --modulepath=./ option in the puppet module install command. Line 2 says that the module is going to be installed from https://forgeapi.puppetlabs.com/, which is the address for Puppet Forge. Line 3 is fairly self-explanatory and indicates that the installation process is running. Lines 4 and 5 tell us that the puppetlabs-apache module was installed in the current /media/sf_learning working directory. Line 6 indicates that as part of the puppetlabs-apache module installation, a puppetlabs-concat dependency module was also installed. Line 7 lists another dependency module called puppetlabs-stdlib that got installed in the process. Now you can run the tree -L 1 command to see what new directories got created in /media/sf_learning as a result of the puppet module install command: # tree -L 1 ├── apache ├── concat ├── stdlib └── webapp 4 directories, 0 files The argument -L 1 in the tree command specifies that it should only traverse one level of directory hierarchy. Installing Apache HTTP Server Now that the puppetlabs-apache module is installed in the filesystem, we can proceed with the Apache HTTP Server installation. Earlier, we talked about how a Puppet class can be referenced with the include keyword. Let's see how this works in practice by adding the include apache statement to our webapp class, and then applying the webapp class from the command line. Open the webapp/manifests/init.pp file in your preferred text editor, and add the include apache statement inside the webapp class. I like to place the include statements at the beginning of the class before any resource statement. In my text editor, the webapp class looks like the following after the include statement has been added to it:   Once you have saved the webapp/manifests/init.pp file, you can apply the webapp class with the following command: # puppet apply --modulepath=./ webapp/tests/init.pp This time, the command output is much longer compared to what it was when we applied the webapp class for the first time. In fact, the output is too long to be included in full, so I'm only going to show you the last two lines of the Puppet report, which shows you the step where the state of the Service[httpd] resource has changed from stopped to running: Notice: /Stage[main]/Apache::Service/Service[httpd]/ensure: ensure changed 'stopped' to 'running'Notice: Finished catalog run in 65.20 seconds Summary So we have now come to the end of this article. I hope you found the content useful and not too challenging. One of the key deliverables of this article was to experiment with Puppet modules and learn how to create your own module
Read more
  • 0
  • 0
  • 5813

article-image-packt-make-epub-downloads-available-its-website
Packt
20 Jul 2010
2 min read
Save for later

Packt to make ePub downloads available from its website

Packt
20 Jul 2010
2 min read
ePub (short for electronic publication) is a free and open eBook standard by the International Digital Publishing Forum (IDPF). ePub allows greater flexibility with content. With an ePub-formatted book, the display of text can be optimized for the reader's device.  Other ePub features include improved design and layout, Inline raster and vector images, better search functionality, while enabling DRM protection and embedded metadata. The company’s marketing manager Damian Carvill said “Packt listens to all feedback from customers and attempts to act on it accordingly. After receiving a number of requests, we made it a priority to convert all of our existing eBooks into the ePub format. All of our future books, and we hope to publish over 20 in July, will also be available in this popular eBook format.” Packt is inviting all customers, who have purchased an eBook, to download the ePub version of the book and enjoy its features and great flexibility. Alternatively, customers can sample the ePub format by accessing one of Packt’s free eBooks. All purchases of new eBooks from today will be made available to download as an ePub file, as well as the standard PDF. Packt ePub formatted eBooks are available from Tuesday 20th July 2010. To access your first Packt ePub eBook, either previously purchased or one of Packt’s free eBooks, please log into www.PacktPub.com and go to My account.  
Read more
  • 0
  • 0
  • 5812

article-image-hierarchical-clustering
Packt
07 Feb 2017
6 min read
Save for later

Hierarchical Clustering

Packt
07 Feb 2017
6 min read
In this article by Atul Tripathi, author of the book Machine Learning Cookbook, we will cover hierarchical clustering with a World Bank sample dataset. (For more resources related to this topic, see here.) Introduction Hierarchical clustering is one of the most important methods in unsupervised learning is hierarchical clustering. In hierarchical clustering for a given set of data points, the output is produced in the form of a binary tree (dendrogram). In the binary tree, the leaves represent the data points while internal nodes represent nested clusters of various sizes. Each object is assigned to a separate cluster. Evaluation of all the clusters shall take place based on a pairwise distance matrix. The distance matrix shall be constructed using distance values. The pair of clusters with the shortest distance must be considered. The pair identified should then be removed from the matrix and merged together. The merged clusters must be distance must be evaluated with the other clusters and the distance matrix must be updated. The process must be repeated until the distance matrix is reduced to a single element. Hierarchical clustering - World Bank sample dataset One of the main goals for establishing the World Bank has been to fight and eliminate poverty. Continuous evolution and fine tuning its policies in the ever-evolving world has been helping the institution to achieve the goal of poverty elimination. The barometer of success in elimination of poverty is measured in terms of improvement of each of the parameters in health, education, sanitation, infrastructure, and other services needed to improve the lives of poor. The development gains which will ensure the goals must be pursued in an environmentally, socially, and economically sustainable manner. Getting ready In order to perform hierarchical clustering, we shall be using a dataset collected from the World Bank dataset.  Step 1 - Collecting and describing data The dataset titled WBClust2013 shall be used. This is available in the CSV format titled WBClust2013.csv. The dataset is in standard format. There are 80 rows of data. There are 14 variables. The numeric variables are: new.forest Rural log.CO2 log.GNI log.Energy.2011 LifeExp Fertility InfMort log.Exports log.Imports CellPhone RuralWater Pop The non-numeric variables are: Country How to do it Step 2 - exploring data Version info: Code for this page was tested in R version 3.2.3 (2015-12-10) Let's explore the data and understand the relationships among the variables. We'll begin by importing the CSV file named WBClust2013.csv. We will be saving the data to the wbclust data frame: > wbclust=read.csv("d:/WBClust2013.csv",header=T) Next, we shall print the wbclust data frame. The head() function returns the wbclust data frame. The wbclust data frame is passed as an input parameter: > head(wbclust) The results are as follows: Step 3 - transforming data Centering variables and creating z-scores are two common data analysis activities to standardize data. The numeric variables mentioned above need to create z-scores. The scale()function is a generic function whose default method centers and/or scales the columns of a numeric matrix. The data frame, wbclust is passed to the scale function. All the numeric fields are only considered. The result is then stored in another data frame, wbnorm. > wbnorm<-scale(wbclust[,2:13]) > wbnorm The results are as follows: All data frames have a row names attribute. In order to retrieve or set the row or column names of a matrix-like object, the rownames()function is used. The data frame, wbclust with the first column is passed to the rownames()function. > rownames(wbnorm)=wbclust[,1] > rownames(wbnorm) The call to the function rownames(wbnorm)results in display of the values from the first column. The results are as follows: Step 4 - training and evaluating the model performance The next step is about training the model. The first step is to calculate the distance matrix. The dist()function is used. Using the specified distance measure, distances between the rows of a data matrix are computed. The distance measure used can be Euclidean, maximum, Manhattan, Canberra, binary, or Minkowski. The distance measure used is Euclidean. The Euclidean distance calculates the distance between two vectors as sqrt(sum((x_i - y_i)^2)).The result is then stored in a new data frame, dist1. > dist1<-dist(wbnorm, method="euclidean") The next step is to perform clustering using Ward's method. The hclust() function is used. In order to perform cluster analysis on a set of dissimilarities of the n objects, the hclust()function is used. At the first stage, each of the objects is assigned to its own cluster. After which, at each stage the algorithm iterates and joins two of the most similar clusters. This process will continue till there is just a single cluster left. The hclust() function requires that we provide the data in the form of a distance matrix. The dist1 data frame is passed. By default, the complete linkage method is used. There are multiple agglomeration methods which can be used. Some of the agglomeration methods could be ward.D, ward.D2, single, complete, average. > clust1<-hclust(dist1,method="ward.D") > clust1 The call to the function, clust1results in display of the agglomeration methods used, the manner in which the distance is calculated, and the number of objects. The results are as follows: Step 5 - plotting the model The plot()function is a generic function for plotting of R objects. Here, the plot() function is used to draw the dendrogram: > plot(clust1,labels= wbclust$Country, cex=0.7, xlab="",ylab="Distance",main="Clustering for 80 Most Populous Countries") The result is as follows: The rect.hclust() function highlights the clusters and draws the rectangles around the branches of the dendrogram. The dendrogram is first cut at a certain level followed by drawing a rectangle around the selected branches. The object, clust1 is passed as an object to the function along with the number of clusters to be formed: > rect.hclust(clust1,k=5) The result is as follows: The cuts()function shall cut the tree into multiple groups on the basis of the desired number of groups or the cut height. Here, clust1 is passed as an object to the function along with the number of the desired group: > cuts=cutree(clust1,k=5) > cuts The result is as follows: Getting the list of countries in each group. The result is as follows: Summary In this article we covered hierarchical clustering by collecting, exploring its contents, transforming the data. We trained and evaluated it by using distance matrix and finally plotted the data as a dendrogram. Resources for Article: Further resources on this subject: Supervised Machine Learning [article] Specialized Machine Learning Topics [article] Machine Learning Using Spark MLlib [article]
Read more
  • 0
  • 0
  • 5811
article-image-modx-web-development-creating-lists
Packt
10 Mar 2011
7 min read
Save for later

MODx Web Development: Creating Lists

Packt
10 Mar 2011
7 min read
Menu details in document properties Every resource that can be shown in a menu must have the Shown in Menu option enabled in the resource's setting page. The Resource setting page also has two other options related to menus: Menu title—what to show in the menu. The resource title is used, if this value is left blank. Menu index—when a list of the resources that are to be listed in the menu is created, the menu index can be used to sort the resources in the required order. Menu index is a number, and when creating lists we can specify how we want to use the index. Authentication and authorization When creating the list of resources, WayFinder lists only those resources that are accessible by the user depending on the access permissions set for each resource, and the web user group to which the user belongs. Getting to know WayFinder WayFinder is a snippet that outputs the structure of the resources as reflected in the resource tree. It creates the lists of all the resources that can be accessed by the current user, from those that been marked as Shown in Menu in the resource properties. Let's try out an exercise to discover WayFinder. Create a new resource. Set the name as testing wayfinder. Choose the template as (blank). Place the following as the content: [[Wayfinder?startId=`0` ]] Save the document, and then preview it. You will see a screen like the one shown in the following screenshot: Notice that WayFinder has created a list of all of the resources, even the ones from the sample site. Each item is a link, so clicking on it leads you to the corresponding document. The generated HTML will look like the following example: <ul><li><a href="http://localhost/learningMODx/" title="Home" >Home</a></li><li><a href="/learningMODx/index.php?id=2" title="Blog" >Blog</a></li><li><a href="/learningMODx/index.php?id=15" title="MODx Features">Features</a><ul><li><a href="/learningMODx/index.php?id=16"title="Ajax" >Ajax</a></li><li><a href="/learningMODx/index.php?id=22" title="Menus and Lists">Menus and Lists</a></li><li><a href="/learningMODx/index.php?id=14" title="Content Management">Manage Content</a></li><li class="last"><a href="/learningMODx/index.php?id=24"title="Extendable by design" >Extendability</a></li></ul></li><li><a href="/learningMODx/index.php?id=33" title="Getting Help">Getting Help</a></li><li><a href="/learningMODx/index.php?id=32" title="Design" >Design</a></li><li><a href="/learningMODx/index.php?id=53" title="Signup Form">Signup Form</a></li><li><a href="/learningMODx/index.php?id=6" title="Contact Us" >Contactus</a></li><li><a href="/learningMODx/index.php?id=54" title="Getting to knowditto" >Getting to know ditto</a><ul><li><a href="/learningMODx/index.php?id=55" title="Sports RSS" >Sports RSS</a></li><li><a href="/learningMODx/index.php?id=56" title="Lifestyle RSS">Lifestyle RSS</a></li><li class="last"><a href="/learningMODx/index.php?id=57" title="ITRSS" >IT RSS</a></li></ul></li><li class="last active"><a href="/learningMODx/index.php?id=58"title="testing wayfinder" >testing wayfinder</a></li></ul> As seen in the preceding output, the generated list is just a set of <ul> and <li> tags. Let's go step-by-step, in understanding how the preceding output can be customized and themed, starting with menus of one level. Theming To be able to theme the list generated by WayFinder to appear as menus, we need to understand how WayFinder works in more detail. In this section, we will show you step-by-step how to create a simple menu without any sub-items, and then proceed to creating menus with sub-items. Creating a simple menu Since, for now, we only want a menu without any submenu items, we have to show resources only from the top level of the resource tree. By default, WayFinder will reflect the complete structure of the resource tree, including the resources within containers, as seen in the preceding screenshot. WayFinder lets you choose the depth of the list via the &level parameter. The parameter &level takes a value indicating the number of levels that WayFinder should include in the menu. For our example, because we only want a simple menu with no submenu items, &level is set to 1. Now, let us change the testing wayfinder resource, which we just created, to the following code: [[Wayfinder?startId=`0` &level=`1` ]] Preview the resource now, and you will see that the source code of the generated page in place of Wayfinder is: <ul><li><a href="http://localhost/learningMODx/" title="Home" >Home</a></li><li><a href="/learningMODx/index.php?id=2" title="Blog" >Blog</a></li><li><a href="/learningMODx/index.php?id=15" title="MODx Features">Features</a></li><li><a href="/learningMODx/index.php?id=33" title="Getting Help">Getting Help</a></li><li><a href="/learningMODx/index.php?id=32" title="Design" >Design</a></li><li><a href="/learningMODx/index.php?id=53" title="Signup Form">Signup Form</a></li><li><a href="/learningMODx/index.php?id=6" title="Contact Us" >Contactus</a></li><li><a href="/learningMODx/index.php?id=54" title="Getting to knowditto" >Getting to know ditto</a></li><li class="last active"><a href="/learningMODx/index.php?id=58"title="testing wayfinder" >testing wayfinder</a></li></ul> Now, if we can just give <ul> and <li> respective classes, we can style them to appear as a menu. We can do this by passing the class names to the parameter &rowClass. Change the contents of the preceding testing wayfinder to: <div id="menu">[!Wayfinder?startId=`0` &level=`1` &rowClass=`menu`!]</div> Now, open style.css from the root folder, and change the CSS to the following code. What we are doing is styling the preceding generated list to appear like a menu, by using CSS: * { padding:2; margin:0; border:1; }body { margin:0 20px; background:#8CEC81; }#banner { background: #2BB81B; border-top:5px solid #8CEC81; borderbottom:5px solid #8CEC81; }#banner h1 { padding:10px; }#wrapper { background: #8CEC81; }#container { width: 100%; background: #2BB81B; float: left; }#content { background: #ffffff; height:600px; padding:0 10px 10px10px; clear:both; }#footer { background: #2BB81B; border-top:5px solid #8CEC81; borderbottom:5px solid #8CEC81; }.clearing { clear:both; height:0; }#content #col-1 {float:left;width:500px; margin:0px;padding:0px;}#content #col-2 {float:right; width:300px; margin:0px; padding:30px 010px 25px; border-left:3px solid #99cc66; height:500px;}#content #col-2 div {padding-bottom:20px;}#menu {background:#ffffff;float: left;}#menu ul {list-style: none;margin: 0;padding: 0;width: 48em;float: left;}#menu ul li {display: inline;}#menu a, #menu h2 {font: bold 11px/16px arial, helvetica, sans-serif;display: inline;border-width: 1px;border-style: solid;border-color: #ccc #888 #555 #bbb;margin: 0;padding: 2px 3px;}#menu h2 {color: #fff;background: #000;text-transform: uppercase;}#menu a {color: #000;background: #2BB81B;text-decoration: none;}#menu a:hover {color: #2BB81B;background: #fff;} Also remember to change the template of the resource to the learning MODx default template. Now preview the page, and you will see something like the one shown in the following screenshot: The HTML code returned will be similar to the following: <ul><li class="menu"><a href="http://localhost/learningMODx/"title="Home" >Home</a></li><li class="menu"><a href="/learningMODx/index.php?id=2" title="Blog">Blog</a></li><li class="menu"><a href="/learningMODx/index.php?id=15" title="MODxFeatures" >Features</a></li><li class="menu"><a href="/learningMODx/index.php?id=33"title="Getting Help" >Getting Help</a></li><li class="menu"><a href="/learningMODx/index.php?id=32"title="Design" >Design</a></li><li class="menu"><a href="/learningMODx/index.php?id=53" title="SignupForm" >Signup Form</a></li><li class="menu"><a href="/learningMODx/index.php?id=6" title="ContactUs" >Contact us</a></li><li class="menu"><a href="/learningMODx/index.php?id=54"title="Getting to know ditto" >Getting to know ditto</a></li><li class="menu last active"><a href="/learningMODx/index.php?id=58"title="testing wayfinder" >testing wayfinder</a></li></ul> Notice that for each menu item, the class menu has been applied. Although we have not applied any custom style to the menu class, we have shown you that when you are building more fine-grained menu systems, you have the ability to have every item associated with a class.
Read more
  • 0
  • 0
  • 5804

article-image-debugging-multithreaded-applications-singlethreaded-c
Packt
15 Oct 2009
6 min read
Save for later

Debugging Multithreaded Applications as Singlethreaded in C#

Packt
15 Oct 2009
6 min read
We can identify threads created using both the BackgroundWorker component and the Thread class. We can also identify the main application thread and we learned about the information shown by the Threads window. However, we must debug the encryption process to solve its problem without taking into account the other concurrent threads. How can we successfully debug the encryption engine focusing on one thread and leaving the others untouched? We can use the Threads window to control the execution of the concurrent thread at runtime without having to make changes to the code. This will affect the performance results, but it will allow us to focus on a specific part of the code as if we were working in a single-threaded application. This technique is suitable for solving problems related to a specific part of the code that runs in a thread. However, when there are problems generated by concurrency we must use other debugging tricks that we will be learning shortly. The Threads window does a great job in offering good runtime information about the running threads while offering a simple way to watch, pause, and resume multiple threads. Time for action – Leaving a thread running alone You must run the encryption procedure called by ThreadEncryptProcedure. But you want to focus on just one thread, in order to solve the problem that the FBI agents detected. Changing the code is not an option, because it will take more time than expected, and you might introduce new bugs to the encryption engine. Thus, let's freeze the threads we are not interested in! Now, we are going to leave one encryption thread running alone to focus on its code without the other threads disturbing our debugging procedure: Stay in the project, SMSEncryption. Clear all the breakpoints. Press Ctrl + Shift + F9 or select Debug | Delete AllBreakpoints in the main menu. Make sure the Threads window is visible. Define a breakpoint in the line int liThreadNumber = (int)poThreadParameter; in the ThreadEncryptProcedure procedure code. Enter or copy and paste a long text, using the same lines (with more than 30,000 lines) in the Textbox labeled Original SMS Messages, as shown in the following image: Click on the Run in a thread button. The line with the breakpoint defined in the ThreadEncryptProcedure procedure is shown highlighted as the next statement that will be executed. The current thread will be shown with a yellow arrow on the left in the Threads window. Right-click on each of the other encryption threads and select Freeze in the context menu that appears, in order to suspend them. If the current thread is Encryption #1 and there are four cores available, you will freeze the following threads—Encryption #0, Encryption #2, and Encryption #3. Right-click on the Main thread and select Freeze in the context menu that appears, in order to suspend it (we do not want the BackgroundWorker to start and interfere with our work). The only working thread that matters will be Encryption #1, as shown in the following image: Run the code step-by-step inspecting values as you do with single-threaded applications. What just happened? It is easy to debug a multi hreaded application focusing on one thread instead of trying to do it with all the threads running at the same time. We could transform a complex multi threaded application into a single-threaded application without making changes to the code. We did it at runtime using the multithreading debugging features offered by the C# IDE. We suspended the execution of the concurrent threads that would disturb our step-by-step execution. Thus, we could focus on the code being executed by just one encryption thread. Freezing and thawing threads Freezing a thread suspends its execution. However, in the debugging process, we would need to resume the thread execution. It can be done at any point of ti me by right-clicking on a suspended thread and selecting Thaw in the context menu that appears, as shown in the following image: By Freezing and Thawing threads (suspending and resuming), we can have an exhaustive control over the threads running during the debugging process. It helps a lot when we have to solve bugs related to concurrency as we can easily analyze many contexts without making changes to the code—which could generate new bugs. Nevertheless, when developing multithreaded applications, we must always test the execution with many concurrent threads running to make sure it does not have concurrency bugs. The debugging techniques allow us to isolate the code for evaluation purposes, but the final tests must use the full multithreading potential. Viewing the call stack for each running thread Each thread has its own independent stack. Using the Call Stack window, we can move through the methods that were called, as we are used to doing so in single-threaded applications. The main difference in doing this with multithreaded applications is that when the active thread changes, the Call Stack window will also show different content. Debugging a multi hreaded application using the techniques we are learning is an excellent way to understand how the different threads run and will improve our parallel programming skills. To show the call stack for the active thread, press Ctrl + Alt + C or go to Debug | Windows | Call Stack in the main menu. Make sure the Threads window is also visible to take into account the active thread when analyzing the call stack, as shown in the following image: Have a go hero – Debugging and enhancing the encryption algorithm Using the multithreaded debugging techniques we have learned so far, develop a new version of this application with the encryption problem solved. Take into account everything we have studied about freezing and thawing threads. Check the randomly generated garbage and the way it is applied to the generated encrypted string. Making some changes to it, you can have a robust encryption process that differentiates each output with the same input text. You can improve the new versions by using new randomly generated garbage to enhance the encryption algorithms. Oh no! You have to explain to the agents the changes you made to the encryption procedure, and how it works.  
Read more
  • 0
  • 0
  • 5802
Modal Close icon
Modal Close icon