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

How-To Tutorials

7018 Articles
article-image-create-simple-plugin-melonjs-games
Ellison Leao
10 Nov 2014
4 min read
Save for later

Creating a simple plugin for MelonJS games

Ellison Leao
10 Nov 2014
4 min read
If you are not familiar with the great MelonJS game framework, please go to their official page and read about the great things you can do with this awesome tool. In this post I will teach you how to create a simple plugin to use in your MelonJS game. First, you need to understand the plugin structure: (function($) { myPlugin = me.plugin.Base.extend({ // minimum melonJS version expected version : "1.0.0", init : function() { // call the parent constructor this.parent(); this.myVar = null; }, }); })(window); As you can see, there are no real difficulties in creating new plugins. You just have to create a me class inheriting from the me.plugin.Base class, passing the minimum melonJS version this plugin will use. If you need to persist some variables, you can override the init method just like the code from the start. For this plugin I will create a Clay.io leaderboard integration for a game. The code for the plugin is as follows: /* * MelonJS Game Engine * Copyright (C) 2011 - 2013, Olivier Biot, Jason Oster * http://www.melonjs.org * * Clay.io API plugin * */ (function($) { /** * @class * @public * @extends me.plugin.Base * @memberOf me * @constructor */ Clayio = me.plugin.Base.extend({ // minimum melonJS version expected version : "1.0.0", gameKey: null, _leaderboard: null, init : function(gameKey, options) { // call the parent constructor this.parent(); this.gameKey = gameKey; Clay = {}; Clay.gameKey = this.gameKey; Clay.readyFunctions = []; Clay.ready = function( fn ) { Clay.readyFunctions.push( fn ); }; if (options === undefined) { options = { debug: false, hideUI: false } } Clay.options = { debug: options.debug === undefined ? false: options.debug, hideUI: options.hideUI === undefined ? false: options.hideUI, fail: options.fail } window.onload = function() { var clay = document.createElement("script"); clay.async = true; clay.src = ( "https:" == document.location.protocol ? "https://" : "http://" ) + "cdn.clay.io/api.js"; var tag = document.getElementsByTagName("script")[0]; tag.parentNode.insertBefore(clay, tag); } }, leaderboard: function(id, score, callback) { if (!id) { throw "You must pass a leaderboard id"; } // we can get the score directly from game.data.score if (!score){ score = game.data.score; } var leaderboard = new Clay.Leaderboard({id: id}); this._leaderboard = leaderboard; if (!callback) { this._leaderboard.post({score: score}, callback); }else{ this._leaderboard.post({score: score}); } }, showLeaderBoard: function(id, options, callback) { if (!options){ options = {}; } if (options.limit === undefined){ options.limit = 10; } if (!this._leaderboard) { if (id === undefined) { throw "The leaderboard was not defined before. You must pass a leaderboard id"; } var leaderboard = new Clay.Leaderboard({id: id}); this._leaderboard = leaderboard; } this._leaderboard.show(options, callback); } }); })(window); Let me explain how all of this works: The init method will receive your Clay.io gamekey and initialize the Clay.io API file asynchronously. The leaderboard receives a Clay.io leaderboard ID and a score value. Then, the method creates a leaderboard instance and adds the passed score to the Clay.io leaderboard. If no ID is passed, the function throws an error. The showLeaderboard method is an event that shows the Clay.io leaderboard modal on the screen. If you previously called the leaderboard method, there is no need to pass the leaderboard ID again. To use this plugin in your game, first register the plugin in your game.js file. On the game.onload method add the following code: window.onload(function() { me.plugin.register.defer(this, Clayio, "clay"); }); Due to a Clay.io bug you need to add the socket.io.js script into the index.html file manually. Place the following code into the file <head>: <script src='http://api.clay.io/socket.io/socket.io.js'></script> Now, if you want to call the leaderboard method, just add the following code into your scene: me.plugin.clay.leaderboard(leaderboardId); And that's it! I hope I’ve shown you how easy it is to create plugins for MelonJS. About The Author Ellison Leão (@ellisonleao) is a passionate software engineer with more than 6 years of experience in web projects and a contributor to the MelonJS framework and other open source projects. When he is not writing games, he loves to play drums.
Read more
  • 0
  • 0
  • 2035

article-image-making-large-scale-led-art-with-fadecandy
Michael Ang
10 Nov 2014
6 min read
Save for later

Making Large-Scale LED Art with FadeCandy

Michael Ang
10 Nov 2014
6 min read
Building projects with programmable LEDs can be very satisfying. With a few lines of code, you can create an awesome animated pattern of light. If you've programmed with an Arduino, you certainly remember the first time you got an LED to blink! From there, you probably wanted to go larger. Arduino is an excellent platform for projects with a small number of LEDs, but at a certain point the small micro-controller reaches its limit. Ardent Mobile Cloud Platform, the project that sparked FadeCandy. Photo by Aaron Muszalski, used under CC-BY. FadeCandy is an alternative way to drive potentially thousands of LEDs, and is an excellent way to go when you have a project larger than Arduino can handle. FadeCandy also provides sophisticated techniques to make your animations buttery smooth—very important when you aren't going for a "chunky" look with your lighting. A typical problem when using LEDs is getting a smooth fade to off or a low brightness. Usually there's a pronounced "stair step" or chunkiness as the LED approaches minimum brightness. The FadeCandy board uses dithering and interpolation to smooth between color values, giving you more nuanced color and smoother animation. With FadeCandy, your light palette can now include "subtle and smooth" as well as "blinky and bright." Two FadeCandy boards The FadeCandy board connects to your computer over USB and can drive up to 8 strips of 64 LEDs. FadeCandy uses the popular WS281x RGB LEDs, which are available online, for example, NeoPixels from Adafruit. Multiple boards can be connected to the host computer, and with 512 LEDs per board, you can create quite large light projects! The host computer runs a piece of software called the FadeCandy server (fcserver). The program (called the "client") that creates the light pattern is separate from the server and can be written in a variety of different programming languages. For example, you can write your animation program in Processing and your Processing sketch will send the colors for the pixels to the FadeCandy server, which sends the data over USB to the FadeCandy hardware boards. It's also possible to make a web page that connects to the FadeCandy server, or to use Python or Node.js. This flexibility means that you can use a powerful desktop programming language that supports, for example, video playback or camera processing. The downside is that you need a host computer with a USB to drive the FadeCandy hardware boards, but the host computer could be a small one, such as the Raspberry Pi.   FadeCandy connected to computer via USB and an LED strip via a breadboard. The LED strip is connected to a separate 5V power supply (not shown). When using a small number of LEDs with an Arduino, you can get away with powering the LEDs from the same power supply as the Arduino. Since FadeCandy is designed to use a large number of LEDs at once, you'll need a separate power supply to power the LEDs (you can't just power them from the USB connection). This is actually a good thing, since it makes you think about providing enough juice to run all the LEDs. For a full guide on setting up a FadeCandy board and software, I recommend the in-depth tutorial LED Art with FadeCandy. Once you have the hardware set up, there are two pieces of software you need to run. The first is the FadeCandy server (fcserver). The server connects to the FadeCandy boards over USB and listens for clients to connect over the network. The client software is responsible for generating the pixels that you want to show and then passing this data to the server. The client software is where you create your fancy animation, handle user interaction, analyze audio, or do whatever processing is needed to generate the colors for your LEDs. Client program in Processing Let's look at one of the examples included with the FadeCandy source code. The example is written in Processing and plays back an animation of fire on a strip of 64 LEDs. The Processing code loads a picture of flames and scrolls the image vertically over the strip of LEDs. The white dots in the screenshot represent the LEDs in the strip—at each of the dots, the color from the Processing sketch is sampled and sent to the corresponding LED. The nice thing about using Processing to make the animation is that it's easy to load an image or perform other more complicated operations and we get to see what's happening onscreen. With the large amount of memory and CPU on a laptop computer, we could also load a video of a fire burning and have that show on the LEDs. The light from the LEDs in this example is quite pleasing. Projected on a wall or other surface, the light ripples smoothly. It's possible to turn off the dithering and interpolation that FadeCandy provides (for example, with this Python config utility) and you can see that these techniques do lead to smoother animation, especially at lower brightness levels. With the dithering and interpolation turned on, the motion is more fluid, giving more of an illusion of continuous movement rather than individual LEDs changing. The choice of using FadeCandy or Arduino to control LEDs comes down largely to a question of scale. For projects using a small number of LEDs, using an Arduino makes it easy to make the project standalone and run on battery power. For example, in my Chrysalis light sculpture, I use an Arduino to drive 32 LEDs interpolating between colors from an image. I was able to fit the image into the onboard memory of the Arduino by making it quite small (31x16 RGB pixels, for a grand total of 1,488 bytes). Getting smooth fading with 32 LEDs on an Arduino is certainly possible, but using hundreds of LEDs would be out of the question. FadeCandy-driven LEDs in a Polycon light sculpture. FadeCandy was designed for projects that are too big to fit on a single Arduino. Where the total memory on an Arduino is measured in kilobytes, the RAM on a Raspberry Pi is hundreds of megabytes, and on a laptop you're talking gigabytes. You can use the processing power of your laptop (or single board computer) to analyze audio, play back video, or do heavy computation that would be hard on a microcontroller. By providing easy interfacing and smooth fading, FadeCandy really opens up what is possible for artistic expression with programmable lighting. I for one welcome the new age of buttery smooth LED light art! FadeCandy is a project by Micah Elizabeth Scott produced in collaboration with Adafruit. About the author: Michael Ang is a Berlin-based artist and engineer working at the intersection of art, engineering, and the natural world. His latest project is the Polygon Construction Kit, a toolkit that bridges the virtual and physical realms by constructing real-world objects from simple 3D models. He is one of the organizers of Art Hack Day, an event for hackers whose medium is tech and artists whose medium is technology. Into Arduino? Check out our Arduino page for our newest and most popular releases. Begin your adventure through creative hardware today!
Read more
  • 0
  • 0
  • 6048

article-image-configuring-distributed-rails-applications-chef-part-2
Rahmal Conda
07 Nov 2014
9 min read
Save for later

Configuring Distributed Rails Applications with Chef: Part 2

Rahmal Conda
07 Nov 2014
9 min read
In my Part 1 post, I gave you the low down about Chef. I covered what it’s for and what it’s capable of. Now let’s get into some real code and take a look at how you install and run Chef Solo and Chef Server. What we want to accomplish First let’s make a list of some goals. What are we trying to get out of deploying and provisioning with Chef? Once we have it set up, provisioning a new server should be simple; no more than a few simple commands. We want it to be platform-agnostic so we can deploy any VPS provider we choose with the same scripts. We want it to be easy to follow and understand. Any new developer coming later should have no problem figuring out what’s going on. We want the server to be nearly automated. It should take care of itself as much as possible, and alert us if anything goes wrong. Before we start, let’s decide on a stack. You should feel free to run any stack you choose. This is just what I’m using for this post setup: Ubuntu 12.04 LTS RVM Ruby 1.9.3+ Rails 3.2+ Postgres 9.3+ Redis 3.1+ Chef Git Now that we’ve got that out of the way, let’s get started! Step 1: Install the tools First, make sure that all of the packages we download to our VPS are up to date: ~$ sudo apt-get update Next, we'll install RVM (Ruby Version Manager). RVM is a great tool for installing Ruby. It allows you to use several versions of Ruby on one server. Don't get ahead of yourself though; at this point, we only care about one version. To install RVM, we’ll need curl: ~$ sudo apt-get install curl We also need to install Git. Git is an open source distributed version control system, primarily used to maintain software projects. (If you didn't know that much, you're probably reading the wrong post. But I digress!): ~$ sudo apt-get install git Now install RVM with this curl command: ~$ curl -sSL https://get.rvm.io | bash -s stable You’ll need to source RVM (you can add this to your bash profile): ~$ source ~/.rvm/scripts/rvm In order for it to work, RVM has some of its own dependencies that need to be installed. To automatically install them, use the following command: ~$ rvm requirements Once we have RVM set up, installing Ruby is simple: ~$ rvm install 1.9.3 Ruby 1.9.3 is now installed! Since we'll be accessing it through a tool that can potentially have a variety of Ruby versions loaded, we need to tell the system to use this version as the default: ~$ rvm use 1.9.3 --default Next we'll make sure that we can install any Ruby Gem we need into this new environment. We'll stick with RVM for installing gems as well. This'll ensure they get loaded into our Ruby version properly. Run this command: ~$ rvm rubygems current Don’t worry if it seems like you’re setting up a lot of things manually now. Once Chef is set up, all of this will be part of your cookbooks, so you’ll only have to do this once. Step 2: Install Chef and friends First, we'll start off by cloning the Opscode Chef repository: ~$ git clone git://github.com/opscode/chef-repo.git chef With Ruby and RubyGems set up, we can install some gems! We’ll start with a gem called Librarian-Chef. Librarian-Chef is sort of a Rails Bundler for Chef cookbooks. It'll download and manage cookbooks that you specify in Cheffile. Many useful cookbooks are published by different sources within the Chef community. You'll want to make use of them as you build out your own Chef environment. ~$ gem install librarian-chef  Initialize Librarian in your Chef repository with this command: ~$ cd chef ~/chef$ librarian-chef init This command will create a Cheffile in your Chef repository. All of your dependencies should be specified in that file. To deploy the stack we just built, your Cheffile should look like this: 1 site 'http://community.opscode.com/api/v1' 2 cookbook 'sudo' 3 cookbook 'apt' 4 cookbook 'user' 5 cookbook 'git' 6 cookbook 'rvm' 7 cookbook 'postgresql' 8 cookbook 'rails' ~ Now use Librarian to pull these community cookbooks: ~/chef$ librarian-chef install Librarian will pull the cookbooks you specify, along with their dependencies, to the cookbooks folder and create a Cheffile.lock file. Commit both Cheffile and Cheffile.lock to your repo: ~/chef$ git add Cheffile Cheffile.lock ~/chef$ git commit -m “updated cookbooks list” There is no need to commit the cookbooks folder, because you can always use the install command and Librarian will pull the same group of cookbooks with the correct versions. You should not touch the cookbooks folder—let Librarian manage it for you. Librarian will overwrite any changes you make inside that folder. If you want to manually create and manage cookbooks, outside of Librarian, add a new folder, like local-cookbooks, for instance. Step 3: Cooking up somethin’ good! Now that you see how to get the cookbooks, you can create your roles. You use roles to determine what role a server instance would have in you server stack, and you specify what that role would need. For instance, your Database Server role would most likely need a Postgresql server (or you DB of choice), a DB client, user authorization and management, while your Web Server would need Apache (or Nginx), Unicorn, Passenger, and so on. You can also make base roles, to have a basic provision that all your servers would have. Given what we’ve installed so far, our basic configuration might look something like this: name "base" description "Basic configuration for all nodes" run_list( 'recipe[git]', 'recipe[sudo]', 'recipe[apt]', 'recipe[rvm::user]', 'recipe[postgresql::client]' ) override_attributes( authorization: { sudo: { users: ['ubuntu'], passwordless: true } }, rvm: { rubies: ['ruby-1.9.3-p125'], default_ruby: 'ruby-1.9.3-p125', global_gems: ['bundler', 'rake'] } ) ~ Deploying locally with Chef Solo: Chef Solo is a Ruby gem that runs a self-contained Chef instance. Solo is great for running your recipes locally to test them, or to provision development machines. If you don’t have a hosted Chef Server set up, you can use Chef Solo to set up remote servers too. If your architecture is still pretty small, this might be just what you need. We need to create a Chef configuration file, so we’ll call it deploy.rb: root = File.absolute_path(File.dirname(__FILE__)) roles = File.join(root, 'cookbooks') books = File.join(root, 'roles') file_cache_path root cookbook_path books role_path roles ~ We’ll also need a JSON-formatted configuration file. Let’s call this one deploy.json: { "run_list": ["recipe[base]"] } ~ Now run Chef with this command: ~/chef$ sudo chef-solo -j deploy.json -c deploy.rb Deploying to a new Amazon EC2 instance: You’ll need the Chef server for this step. First you need to create a new VPS instance for your Chef server and configure it with a static IP or a domain name, if possible. We won’t go through that here, but you can find instructions for setting up a server instance on EC2 with a public IP and configuring a domain name in the documentation for your VPS. Once you have your server instance set up, SSH onto the instance and install Chef server. Start by downloading the dep package using the wget tool: ~$ wget https://opscode-omnibus-packages.s3.amazonaws.com/ ubuntu/12.04/x86_64/chef-server_11.0.10-1.ubuntu.12.04_amd64.deb Once the dep package has downloaded, install Chef server like so: ~$ sudo dpkg -i chef-server* When it completes, it will print to the screen an instruction that you need to run this next command to actually configure the service for your specific machine. This command will configure everything automatically: ~$ sudo chef-server-ctl reconfigure Once the configuration step is complete, the Chef server should be up and running. You can access the web interface immediately by browsing to your server's domain name or IP address. Now that you’ve got Chef up and running, install the knife EC2 plugin. This will also install the knife gem as a dependency: ~$ gem install knife-ec2 You now have everything you need! So create another VPS to provision with Chef. Once you do that, you’ll need to copy your SSH keys over: ~$ ssh-copy-id root@yourserverip You can finally provision your server! Start by installing Chef on your new machine: ~$ knife solo prepare root@yourserverip This will generate a file, nodes/yourserverip.json. You need to change this file to add your own environment settings. For instance, you will need to add username and password for monit. You will also need to add a password for postgresql to the file. Run the openssl command again to create a password for postgresql. Take the generated password, and add it to the file. Now, you can finally provision your server! Start the Chef command: ~$ knife solo cook root@yourserverip Now just sit back, relax and watch Chef cook up your tasty app server. This process may take a while. But once it completes, you’ll have a server ready for a Rails, Postgres, and Redis! I hope these posts helped you get an idea of how much Chef can simplify your life and your deployments. Here’s a couple of links with more information and references about Chef: Chef community site:http://cookbooks.opscode.com/ Chef Wiki:https://wiki.opscode.com/display/chef/Home Chef Supermarket:https://community.opscode.com/cookbooks?utf8=%E2%9C%93&q=user Chef cookbooks for busy Ruby developers:http://teohm.com/blog/2013/04/17/chef-cookbooks-for-busy-ruby-developers/ Deploying Rails apps with Chef and Capistrano:http://www.slideshare.net/SmartLogic/guided-exploration-deploying-rails-apps-with-chef-and-capistrano About the author Rahmal Conda is a Software Development Professional and Ruby aficionado from Chicago. After 10 years working in web and application development, he moved out to the Bay Area, eager to join the startup scene. He had a taste of the startup life in Chicago working at a small personal finance company. After that he knew it was the life he had been looking for. So he moved his family out west. Since then he's made a name for himself in the social space at some high profile Silicon Valley startups. Right now he's the one of the Co-founders and Platform Architect of Boxes, a mobile marketplace for the world's hidden treasures.
Read more
  • 0
  • 0
  • 2867

article-image-migrating-wordpress-blog-middleman-and-deploying-amazon-s3
Mike Ball
07 Nov 2014
11 min read
Save for later

Migrating a WordPress Blog to Middleman and Deploying to Amazon S3

Mike Ball
07 Nov 2014
11 min read
Part 1: Getting up and running with Middleman Many of today’s most prominent web frameworks, such as Ruby on Rails, Django, Wordpress, Drupal, Express, and Spring MVC, rely on a server-side language to process HTTP requests, query data at runtime, and serve back dynamically constructed HTML. These platforms are great, yet developers of dynamic web applications often face complex performance challenges under heavy user traffic, independent of the underlying technology. High traffic, and frequent requests, may exploit processing-intensive code or network latency, in effect yielding a poor user experience or production outage. Static site generators such as Middleman, Jeckyll, and Wintersmith offer developers an elegant, highly scalable alternative to complex, dynamic web applications. Such tools perform dynamic processing and HTML construction during build time rather than runtime. These tools produce a directory of static HTML, CSS, and JavaScript files that can be deployed directly to a web server such as Nginx or Apache. This architecture reduces complexity and encourages a sensible separation of concerns; if necessary, user-specific customization can be handled via client-side interaction with third-party satellite services. In this three part series, we'll walk-through how to get started in developing a Middleman site, some basics of Middleman blogging, how to migrate content from an existing WordPress blog, and how to deploy a Middleman blog to production. We will also learn how to create automated tests, continuous integration, and automated deployments. In this part, we’ll cover the following: Creating a basic Middleman project Middleman configuration basics A quick overview of the Middleman template system Creating a basic Middleman blog Why should you use middleman? Middleman is a mature, full-featured static site generator. It supports a strong templating system, numerous Ruby-based HTML templating tools such as ERb and HAML, as well as a Sprockets-based asset pipeline used to manage CSS, JavaScript, and third-party client-side code. Middleman also integrates well with CoffeeScript, SASS, and Compass. Environment For this tutorial, I’m using an RVM-installed Ruby 2.1.2. I’m on Mac OSX 10.9.4. Installing middleman Install middleman via bundler: $ gem install middleman Create a basic middleman project called middleman-demo: $ middleman init middleman-demo This results in a middleman-demo directory with the following layout: ├── Gemfile ├── Gemfile.lock ├── config.rb └── source    ├── images    │   ├── background.png    │   └── middleman.png    ├── index.html.erb    ├── javascripts    │   └── all.js    ├── layouts    │   └── layout.erb    └── stylesheets        ├── all.css        └── normalize.css[SB4]  There are 5 directories and 10 files. A quick tour Here are a few notes on the middleman-demo layout: The Ruby Gemfile  cites Ruby gem dependencies; Gemfile.lock cites the full dependency chain, including  middleman-demo’s dependencies’ dependencies The config.rb  houses middleman-demo’s configuration The source directory houses middleman-demo ’s source code–the templates, style sheets, images, JavaScript, and other source files required by the  middleman-demo [SB7] site While a Middleman production build is simply a directory of static HTML, CSS, JavaScript, and image files, Middleman sites can be run via a simple web server in development. Run the middleman-demo development server: $ middleman Now, the middleman-demo site can be viewed in your web browser at  http://localhost:4567. Set up live-reloading Middleman comes with the middleman-livereload gem. The gem detects source code changes and automatically reloads the Middleman app. Activate middleman-livereload  by uncommenting the following code in config.rb: # Reload the browser automatically whenever files change configure :development do activate :livereload end Restart the middleman server to allow the configuration change to take effect. Now, middleman-demo should automatically reload on change to config.rb and your web browser should automatically refresh when you edit the source/* code. Customize the site’s appearance Middleman offers a mature HTML templating system. The source/layouts directory contains layouts, the common HTML surrounding individual pages and shared across your site. middleman-demo uses ERb as its template language, though Middleman supports other options such as HAML and Slim. Also note that Middleman supports the ability embed metadata within templates via frontmatter. Frontmatter allows page-specific variables to be embedded via YAML or JSON. These variables are available in a current_page.data namespace. For example, source/index.html.erb contains the following frontmatter specifying a title; it’s available to ERb templates as current_page.data.title: --- title: Welcome to Middleman --- Currently, middleman-demo is a default Middleman installation. Let’s customize things a bit. First, remove all the contents of source/stylesheets/all.css  to remove the default Middleman styles. Next, edit source/index.html.erb to be the following: --- title: Welcome to Middleman Demo --- <h1>Middleman Demo</h1> When viewing middleman-demo at http://localhost:4567, you’ll now see a largely unstyled HTML document with a single Middleman Demo heading. Install the middleman-blog plugin The middleman-blog plugin offers blog functionality to middleman applications. We’ll use middleman-blog in middleman-demo. Add the middleman-blog version 3.5.3 gem dependency to middleman-demo by adding the following to the Gemfile: gem "middleman-blog", "3.5.3 Re-install the middleman-demo gem dependencies, which now include middleman-blog: $ bundle install Activate middleman-blog and specify a URL pattern at which to serve blog posts by adding the following to config.rb: activate :blog do |blog| blog.prefix = "blog" blog.permalink = "{year}/{month}/{day}/{title}.html" end Write a quick blog post Now that all has been configured, let’s write a quick blog post to confirm that middleman-blog works. First, create a directory to house the blog posts: $ mkdir source/blog The source/blog directory will house markdown files containing blog post content and any necessary metadata. These markdown files highlight a key feature of middleman: rather than query a relational database within which content is stored, a middleman application typically reads data from flat files, simple text files–usually markdown–stored within the site’s source code repository. Create a markdown file for middleman-demo ’s first post: $ touch source/blog/2014-08-20-new-blog.markdown Next, add the required frontmatter and content to source/blog/2014-08-20-new-blog.markdown: --- title: New Blog date: 2014/08/20 tags: middleman, blog --- Hello world from Middleman! Features Rich templating system Built-in helpers Easy configuration Asset pipeline Lots more  Note that the content is authored in markdown, a plain text syntax, which is evaluated by Middleman as HTML. You can also embed HTML directly in the markdown post files. GitHub’s documentation provides a good overview of markdown. Next, add the following ERb template code to source/index.html.erb [SB37] to display a list of blog posts on middleman-demo ’s home page: <ul> <% blog.articles.each do |article| %> <li> <%= link_to article.title, article.path %> </li> <% end %> </ul> Now, when running middleman-demo and visiting http://localhost:4567, a link to the new blog post is listed on middleman-demo ’s home page. Clicking the link renders the permalink for the New Blog blog post at blog/2014-08-20/new-blog.html, as is specified in the blog configuration in config.rb. A few notes on the template code Note the use of a link_to method. This is a built-in middleman template helper. Middleman provides template helpers to simplify many common template tasks, such as rendering an anchor tag. In this case, we pass the link_to method two arguments, the intended anchor tag text and the intended href value. In turn, link_to generates the necessary HTML. Also note the use of a blog variable, within which an article’s method houses an array of all blog posts. Where did this come from?  middleman-demo is an instance of  Middleman::Application;  a blog  method on this instance. To explore other Middleman::Application methods, open middleman-demo via the built-in Middleman console by entering the following in your terminal: $ middleman console To view all the methods on the blog, including the aforementioned articles method, enter the following within the console: 2.1.2 :001 > blog.methods To view all the additional methods, beyond the blog, available to the Middleman::Application instance, enter the following within the console: 2.1.2 :001 > self.methods More can be read about all these methods on Middleman::Application’s rdoc.info class documentation. Cleaner URLs Note that the current new blog URL ends in .html. Let’s customize middleman-demo to omit .html from URLs. Add the following config.rb: activate :directory_indexes Now, rather than generating files such as /blog/2014-08-20/new-blog.html,  middleman-demo generates files such as /blog/2014-08-20/new-blog/index.html, thus enabling the page to be served by most web servers at a /blog/2014-08-20/new-blog/ path. Adjusting the templates Let’s adjust our the middleman-demo ERb templates a bit. First, note that <h1>Middleman Demo</h1> only displays on the home page; let’s make it render on all of the site’s pages. Move <h1>Middleman Demo</h1> from  source/index.html.erb  to source/layouts/layout.erb. Put it just inside the <body> tag: <body class="<%= page_classes %>"> <h1>Middleman Demo</h1> <%= yield %> </body> Next, let’s create a custom blog post template. Create the template file: $ touch source/layout/post.erb Add the following to extend the site-wide functionality of source/layouts/layout.erb to  source/layouts/post.erb: <% wrap_layout :layout do %> <h2><%= current_article.title %></h2> <p>Posted <%= current_article.date.strftime('%B %e, %Y') %></p> <%= yield %> <ul> <% current_article.tags.each do |tag| %> <li><a href="/blog/tags/<%= tag %>/"><%= tag %></a></li> <% end %> </ul> <% end %> Note the use of the wrap_layout  ERb helper.  The wrap_layout ERb helper takes two arguments. The first is the name of the layout to wrap, in this case :layout. The second argument is a Ruby block; the contents of the block are evaluated within the <%= yield %> call of source/layouts/layout.erb. Next, instruct  middleman-demo  to use  source/layouts/post.erb  in serving blog posts by adding the necessary configuration to  config.rb : page "blog/*", :layout => :post Now, when restarting the Middleman server and visiting  http://localhost:4567/blog/2014/08/20/new-blog/,  middleman-demo renders a more comprehensive blog template that includes the post’s title, date published, and tags. Let’s add a simple template to render a tags page that lists relevant tagged content. First, create the template: $ touch source/tag.html.erb And add the necessary ERb to list the relevant posts assigned a given tag: <h2>Posts tagged <%= tagname %></h2> <ul> <% page_articles.each do |post| %> <li> <a href="<%= post.url %>"><%= post.title %></a> </li> <% end %> </ul> Specify the blog’s tag template by editing the blog configuration in config.rb: activate :blog do |blog| blog.prefix = 'blog' blog.permalink = "{year}/{month}/{day}/{title}.html" # tag template: blog.tag_template = "tag.html" end Edit config.rb to configure middleman-demo’s tag template to use source/layout.erb rather than source/post.erb: page "blog/tags/*", :layout => :layout Now, when visiting http://localhost:4567/2014/08/20/new-blog/, you should see a linked list of New Blog’s tags. Clicking a tag should correctly render the tags page. Part 1 recap Thus far, middleman-demo serves as a basic Middleman-based blog example. It demonstrates Middleman templating, how to set up the middleman-blog  plugin, and how to make author markdown-based blog posts in Middleman. In part 2, we’ll cover migrating content from an existing Wordpress blog. We’ll also step through establishing an Amazon S3 bucket, building middleman-demo, and deploying to production. In part 3, we’ll cover how to create automated tests, continuous integration, and automated deployments. About this author Mike Ball is a Philadelphia-based software developer specializing in Ruby on Rails and JavaScript. He works for Comcast Interactive Media where he helps build web-based TV and video consumption applications.
Read more
  • 0
  • 0
  • 20173

article-image-how-to-deploy-a-blog-with-ghost-and-docker
Felix Rabe
07 Nov 2014
6 min read
Save for later

How to Deploy a Blog with Ghost and Docker

Felix Rabe
07 Nov 2014
6 min read
2013 gave birth to two wonderful Open Source projects: Ghost and Docker. This post will show you what the buzz is all about, and how you can use them together. So what are Ghost and Docker, exactly? Ghost is an exciting new blogging platform, written in JavaScript running on Node.js. It features a simple and modern user experience, as well as very transparent and accessible developer communications. This blog post covers Ghost 0.4.2. Docker is a very useful new development tool to package applications together with their dependencies for automated and portable deployment. It is based on Linux Containers (lxc) for lightweight virtualization, and AUFS for filesystem layering. This blog post covers Docker 1.1.2. Install Docker If you are on Windows or Mac OS X, the easiest way to get started using Docker is Boot2Docker. For Linux and more in-depth instructions, consult one of the Docker installation guides. Go ahead and install Docker via one of the above links, then come back and run: docker version You run this in your terminal to verify your installation. If you get about eight lines of detailed version information, the installation was successful. Just running docker will provide you with a list of commands, and docker help <command> will show a command's usage. If you use Boot2Docker, remember to export DOCKER_HOST=tcp://192.168.59.103:2375. Now, to get the Ubuntu 14.04 base image downloaded (which we'll use in the next sections), run the following command: docker run --rm ubuntu:14.04 /bin/true This will take a while, but only for the first time. There are many more Docker images available at the Docker Hub Registry. Hello Docker To give you a quick glimpse into what Docker can do for you, run the following command: docker run --rm ubuntu:14.04 /bin/echo Hello Docker This runs /bin/echo Hello Docker in its own virtual Ubuntu 14.04 environment, but since it uses Linux Containers instead of booting a complete operating system in a virtual machine, this only takes less than a second to complete. Pretty sweet, huh? To run Bash, provide the -ti flags for interactivity: docker run --rm -ti ubuntu:14.04 /bin/bash The --rm flag makes sure that the container gets removed after use, so any files you create in that Bash session get removed after logging out. For more details, see the Docker Run Reference. Build the Ghost image In the previous section, you've run the ubuntu:14.04 image. In this section, we'll build an image for Ghost that we can then use to quickly launch a new Ghost container. While you could get a pre-made Ghost Docker image, for the sake of learning, we'll build our own. About the terminology: A Docker image is analogous to a program stored on disk, while a Docker container is analogous to a process running in memory. Now create a new directory, such as docker-ghost, with the following files — you can also find them in this Gist on GitHub: package.json: {} This is the bare minimum actually required, and will be expanded with the current Ghost dependency by the Dockerfile command npm install --save ghost when building the Docker image. server.js: #!/usr/bin/env node var ghost = require('ghost'); ghost({ config: __dirname + '/config.js' }); This is all that is required to use Ghost as an NPM module. config.js: config = require('./node_modules/ghost/config.example.js'); config.development.server.host = '0.0.0.0'; config.production.server.host = '0.0.0.0'; module.exports = config; This will make the Ghost server accessible from outside of the Docker container. Dockerfile: # DOCKER-VERSION 1.1.2 FROM ubuntu:14.04 # Speed up apt-get according to https://gist.github.com/jpetazzo/6127116 RUN echo "force-unsafe-io" > /etc/dpkg/dpkg.cfg.d/02apt-speedup RUN echo "Acquire::http {No-Cache=True;};" > /etc/apt/apt.conf.d/no-cache # Update the distribution ENV DEBIAN_FRONTEND noninteractive RUN apt-get update RUN apt-get upgrade -y # https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager RUN apt-get install -y software-properties-common RUN add-apt-repository -y ppa:chris-lea/node.js RUN apt-get update RUN apt-get install -y python-software-properties python g++ make nodejs git # git needed by 'npm install' ADD . /src RUN cd /src; npm install --save ghost ENTRYPOINT ["node", "/src/server.js"] # Override ubuntu:14.04 CMD directive: CMD [] EXPOSE 2368 This Dockerfile will create a Docker image with Node.js and the dependencies needed to build the Ghost NPM module, and prepare Ghost to be run via Docker. See Documentation for details on the syntax. Now build the Ghost image using: cd docker-ghost docker build -t ghost-image . This will take a while, but you might have to Ctrl-C and re-run the command if, for more than a couple of minutes, you are stuck at the following step: > node-pre-gyp install --fallback-to-build Run Ghost Now start the Ghost container: docker run --name ghost-container -d -p 2368:2368 ghost-image If you run Boot2Docker, you'll have to figure out its IP address: boot2docker ip Usually, that's 192.168.59.103, so by going to http://192.168.59.103:2368, you will see your fresh new Ghost blog. Yay! For the admin interface, go to http://192.168.59.103:2368/ghost. Manage the Ghost container The following commands will come in handy to manage the Ghost container: # Show all running containers: docker ps -a # Show the container logs: docker logs [-f] ghost-container # Stop Ghost via a simulated Ctrl-C: docker kill -s INT ghost-container # After killing Ghost, this will restart it: docker start ghost-container # Remove the container AND THE DATA (!): docker rm ghost-container What you'll want to do next Some steps that are outside the scope of this post, but some steps that you might want to pursue next, are: Copy and change the Ghost configuration that currently resides in node_modules/ghost/config.js. Move the Ghost content directory into a separate Docker volume to allow for upgrades and data backups. Deploy the Ghost image to production on your public server at your hosting provider. Also, you might want to change the Ghost configuration to match your domain and change the port to 80. How I use Ghost with Docker I run Ghost in Docker successfully over at Named Data Education, a new blog about Named Data Networking. I like the fact that I can replicate an isolated setup identically on that server as well as on my own laptop. Ghost resources Official docs: The Ghost Guide, and the FAQ- / How-To-like User Guide. How To Install Ghost, Ghost for Beginners and All About Ghost are a collection of sites that provide more in-depth material on operating a Ghost blog. By the same guys: All Ghost Themes. Ghost themes on ThemeForest is also a great collection of themes. Docker resources The official documentation provides many guides and references. Docker volumes are explained here and in this post by Michael Crosby. About the Author Felix Rabe has been programming and working with different technologies and companies at different levels since 1993. Currently he is researching and promoting Named Data Networking (http://named-data.net/), an evolution of the Internet architecture that currently relies on the host-bound Internet Protocol. You can find our very best Docker content on our dedicated Docker page. Whatever you do with software, Docker will help you do it better.
Read more
  • 0
  • 0
  • 29148

article-image-alfresco-web-scrpits
Packt
06 Nov 2014
15 min read
Save for later

Alfresco Web Scrpits

Packt
06 Nov 2014
15 min read
In this article by Ramesh Chauhan, the author of Learning Alfresco Web Scripts, we will cover the following topics: Reasons to use web scripts Executing a web script from standalone Java program Invoking a web script from Alfresco Share DeclarativeWebScript versus AbstractWebScript (For more resources related to this topic, see here.) Reasons to use web scripts It's now time to discover the answer to the next question—why web scripts? There are various alternate approaches available to interact with the Alfresco repository, such as CMIS, SOAP-based web services, and web scripts. Generally, web scripts are always chosen as a preferred option among developers and architects when it comes to interacting with the Alfresco repository from an external application. Let's take a look at the various reasons behind choosing a web script as an option instead of CMIS and SOAP-based web services. In comparison with CMIS, web scripts are explained as follows: In general, CMIS is a generic implementation, and it basically provides a common set of services to interact with any content repository. It does not attempt to incorporate the services that expose all features of each and every content repository. It basically tries to cover a basic common set of functionalities for interacting with any content repository and provide the services to access such functionalities. Alfresco provides an implementation of CMIS for interacting with the Alfresco repository. Having a common set of repository functionalities exposed using CMIS implementation, it may be possible that sometimes CMIS will not do everything that you are aiming to do when working with the Alfresco repository. While with web scripts, it will be possible to do the things you are planning to implement and access the Alfresco repository as required. Hence, one of the best alternatives is to use Alfresco web scripts in this case and develop custom APIs as required, using the Alfresco web scripts. Another important thing to note is, with the transaction support of web scripts, it is possible to perform a set of operations together in a web script, whereas in CMIS, there is a limitation for the transaction usage. It is possible to execute each operation individually, but it is not possible to execute a set of operations together in a single transaction as possible in web scripts. SOAP-based web services are not preferable for the following reasons: It takes a long time to develop them They depend on SOAP Heavier client-side requirements They need to maintain the resource directory Scalability is a challenge They only support XML In comparison, web scripts have the following properties: There are no complex specifications There is no dependency on SOAP There is no need to maintain the resource directory They are more scalable as there is no need to maintain session state They are a lightweight implementation They are simple and easy to develop They support multiple formats In a developer's opinion: They can be easily developed using any text editor No compilations required when using scripting language No need for server restarts when using scripting language No complex installations required In essence: Web scripts are a REST-based and powerful option to interact with the Alfresco repository in comparison to the traditional SOAP-based web services and CMIS alternatives They provide RESTful access to the content residing in the Alfresco repository and provide uniform access to a wide range of client applications They are easy to develop and provide some of the most useful features such as no server restart, no compilations, no complex installations, and no need of a specific tool to develop them All these points make web scripts the most preferred choice among developers and architects when it comes to interacting with the Alfresco repository Executing a web script from standalone Java program There are different options to invoke a web script from a Java program. Here, we will take a detailed walkthrough of the Apache commons HttpClient API with code snippets to understand how a web script can be executed from the Java program, and will briefly mention some other alternatives that can also be used to invoke web scripts from Java programs. HttpClient One way of executing a web script is to invoke web scripts using org.apache.commons.httpclient.HttpClient API. This class is available in commons-httpclient-3.1.jar. Executing a web script with HttpClient API also requires commons-logging-*.jar and commons-codec-*.jar as supporting JARs. These JARs are available at the tomcatwebappsalfrescoWEB-INFlib location inside your Alfresco installation directory. You will need to include them in the build path for your project. We will try to execute the hello world web script using the HttpClient from a standalone Java program. While using HttpClient, here are the steps in general you need to follow: Create a new instance of HttpClient. The next step is to create an instance of method (we will use GetMethod). The URL needs to be passed in the constructor of the method. Set any arguments if required. Provide the authentication details if required. Ask HttpClient to now execute the method. Read the response status code and response. Finally, release the connection. Understanding how to invoke a web script using HttpClient Let's take a look at the following code snippet considering the previous mentioned steps. In order to test this, you can create a standalone Java program with a main method and put the following code snippet in Java program and then modify the web script URLs/credentials as required. Comments are provided in the following code snippet for you to easily correlate the previous steps with the code: // Create a new instance of HttpClient HttpClient objHttpClient = new HttpClient(); // Create a new method instance as required. Here it is GetMethod. GetMethod objGetMethod = new GetMethod("http://localhost:8080/alfresco/service/helloworld"); // Set querystring parameters if required. objGetMethod.setQueryString(new NameValuePair[] { new NameValuePair("name", "Ramesh")}); // set the credentials if authentication is required. Credentials defaultcreds = new UsernamePasswordCredentials("admin","admin"); objHttpClient.getState().setCredentials(new AuthScope("localhost",8080, AuthScope.ANY_REALM), defaultcreds); try { // Now, execute the method using HttpClient. int statusCode = objHttpClient.executeMethod(objGetMethod); if (statusCode != HttpStatus.SC_OK) { System.err.println("Method invocation failed: " + objGetMethod.getStatusLine()); } // Read the response body. byte[] responseBody = objGetMethod.getResponseBody(); // Print the response body. System.out.println(new String(responseBody)); } catch (HttpException e) { System.err.println("Http exception: " + e.getMessage()); e.printStackTrace(); } catch (IOException e) { System.err.println("IO exception transport error: " + e.getMessage()); e.printStackTrace(); } finally { // Release the method connection. objGetMethod.releaseConnection(); } Note that the Apache commons client is a legacy project now and is not being developed anymore. This project has been replaced by the Apache HttpComponents project in HttpClient and HttpCore modules. We have used HttpClient from Apache commons client here to get an overall understanding. Some of the other options that you can use to invoke web scripts from a Java program are mentioned in subsequent sections. URLConnection One option to execute web script from Java program is by using java.net.URLConnection. For more details, you can refer to http://docs.oracle.com/javase/tutorial/networking/urls/readingWriting.html. Apache HTTP components Another option to execute web script from Java program is to use Apache HTTP components that are the latest available APIs for HTTP communication. These components offer better performance and more flexibility and are available in httpclient-*.jar and httpcore-*.jar. These JARs are available at the tomcatwebappsalfrescoWEBINFlib location inside your Alfresco installation directory. For more details, refer to https://hc.apache.org/httpcomponents-client-4.3.x/quickstart.html to get an understanding of how to execute HTTP calls from a Java program. RestTemplate Another alternative would be to use org.springframework.web.client.RestTemplate available in org.springframework.web-*.jar located at tomcatwebappsalfrescoWEB-INFlib inside your Alfresco installation directory. If you are using Alfresco community 5, the RestTemplate class is available in spring-web-*.jar. Generally, RestTemplate is used in Spring-based services to invoke an HTTP communication. Calling web scripts from Spring-based services If you need to invoke an Alfresco web script from Spring-based services, then you need to use RestTemplate to invoke HTTP calls. This is the most commonly used technique to execute HTTP calls from Spring-based classes. In order to do this, the following are the steps to be performed. The code snippets are also provided: Define RestTemplate in your Spring context file: <bean id="restTemplate" class="org.springframework.web.client.RestTemplate" /> In the Spring context file, inject restTemplate in your Spring class as shown in the following example: <bean id="httpCommService" class="com.test.HTTPCallService"> <property name="restTemplate" value="restTemplate" /> </bean> In the Java class, define the setter method for restTemplate as follows: private RestTemplate restTemplate; public void setRestTemplate(RestTemplate restTemplate) {    this.restTemplate = restTemplate; } In order to invoke a web script that has an authentication level set as user authentication, you can use RestTemplate in your Java class as shown in the following code snippet. The following code snippet is an example to invoke the hello world web script using RestTemplate from a Spring-based service: // setup authentication String plainCredentials = "admin:admin"; byte[] plainCredBytes = plainCredentials.getBytes(); byte[] base64CredBytes = Base64.encodeBase64(plainCredBytes); String base64Credentials = new String(base64CredBytes); // setup request headers HttpHeaders reqHeaders = new HttpHeaders(); reqHeaders.add("Authorization", "Basic " + base64Credentials); HttpEntity<String> requestEntity = new HttpEntity<String>(reqHeaders); // Execute method ResponseEntity<String> responseEntity = restTemplate.exchange("http://localhost:8080/alfresco/service/helloworld?name=Ramesh", HttpMethod.GET, requestEntity, String.class); System.out.println("Response:"+responseEntity.getBody()); Invoking a web script from Alfresco Share When working on customizing Alfresco Share, you will need to make a call to Alfresco repository web scripts. In Alfresco Share, you can invoke repository web scripts from two places. One is the component level the presentation web scripts, and the other is client-side JavaScript. Calling a web script from presentation web script JavaScript controller Alfresco Share renders the user interface using the presentation web scripts. These presentation web scripts make a call to the repository web script to render the repository data. Repository web script is called before the component rendering file (for example, get.html.ftl) loads. In out-of-the-box Alfresco installation, you should be able to see the components’ presentation web script available under tomcatwebappsshareWEB-INFclassesalfrescosite-webscripts. When developing a custom component, you will be required to write a presentation web script. A presentation web script will make a call to the repository web script. You can make a call to the repository web script as follows: var reponse = remote.call("url of web script as defined in description document"); var obj = eval('(' + response + ')'); In the preceding code snippet, we have used the out-of-the-box available remote object to make a repository web script call. The important thing to notice is that we have to provide the URL of the web script as defined in the description document. There is no need to provide the initial part such as host or port name, application name, and service path the way we use while calling web script from a web browser. Once the response is received, web script response can be parsed with the use of the eval function. In the out-of-the-box code of Alfresco Share, you can find the presentation web scripts invoking the repository web scripts, as we have seen in the previous code snippet. For example, take a look at the main() method in the site-members.get.js file, which is available at the tomcatwebappssharecomponentssite-members location inside your Alfresco installed directory. You can take a look at the other JavaScript controller implementation for out-of-the-box presentation web scripts available at tomcatwebappsshareWEB-INFclassesalfrescosite-webscripts making repository web script calls using the previously mentioned technique. When specifying the path to provide references to the out-of-the-box web scripts, it is mentioned starting with tomcatwebapps. This location is available in your Alfresco installation directory. Invoking a web script from client-side JavaScript The client-side JavaScript control file can be associated with components in Alfresco Share. If you need to make a repository web script call, you can do this from the client-side JavaScript control files generally located at tomcatwebappssharecomponents. There are different ways you can make a repository web script call using a YUI-based client-side JavaScript file. The following are some of the ways to do invoke web script from client-side JavaScript files. References are also provided along with each of the ways to look in the Alfresco out-of-the-box implementation to understand its usage practically: Alfresco.util.Ajax.request: Take a look at tomcatwebappssharecomponentsconsolegroups.js and refer to the _removeUser function. Alfresco.util.Ajax.jsonRequest: Take a look at tomcatwebappssharecomponentsdocumentlibrarydocumentlist.js and refer to the onOptionSelect function. Alfresco.util.Ajax.jsonGet: To directly make a call to get web script, take a look at tomcatwebappssharecomponentsconsolegroups.js and refer to the getParentGroups function. YAHOO.util.Connect.asyncRequest: Take a look at tomcatwebappssharecomponentsdocumentlibrarytree.js and refer to the _sortNodeChildren function. In alfresco.js located at tomcatwebappssharejs, the wrapper implementation of YAHOO.util.Connect.asyncRequest is provided and various available methods such as the ones we saw in the preceding list, Alfresco.util.Ajax.request, Alfresco.util.Ajax.jsonRequest, and Alfresco.util.Ajax.jsonGet can be found in alfresco.js. Hence, the first three options in the previous list internally make a call using the YAHOO.util.Connect.asyncRequest (the last option in the previous list) only. Calling a web script from the command line Sometimes while working on your project, it might be required that from the Linux machine you need to invoke a web script or create a shell script to invoke a web script. It is possible to invoke a web script from the command line using cURL, which is a valuable tool to use while working on web scripts. You can install cURL on Linux, Mac, or Windows and execute a web script from the command line. Refer to http://curl.haxx.se/ for more details on cURL. You will be required to install cURL first. On Linux, you can install cURL using apt-get. On Mac, you should be able to install cURL through MacPorts and on Windows using Cygwin you can install cURL. Once cURL is installed, you can invoke web script from the command line as follows: curl -u admin:admin "http://localhost:8080/alfresco/service/helloworld?name=Ramesh" This will display the web script response. DeclarativeWebScript versus AbstractWebScript The web script framework in Alfresco provides two different helper classes from which the Java-backed controller can be derived. It's important to understand the difference between them. The first helper class is the one we used while developing the web script in this article, org.springframework.extensions.webscripts.DeclarativeWebScript. The second one is org.springframework.extensions.webscripts.AbstractWebScript. DeclarativeWebScript in turn only extends the AbstractWebScript class. If the Java-backed controller is derived from DeclarativeWebScript, then execution assistance is provided by the DeclarativeWebScript class. This helper class basically encapsulates the execution of the web script and checks if any controller written in JavaScript is associated with the web script or not. If any JavaScript controller is found for the web script, then this helper class will execute it. This class will locate the associated response template of the web script for the requested format and will pass the populated model object to the response template. For the controller extending DeclarativeWebScript, the controller logic for a web script should be provided in the Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache) method. Most of the time while developing a Java-backed web script, the controller will extend DeclarativeWebScript only. AbstractWebScript does not provide execution assistance in the way DeclarativeWebScript does. It gives full control over the entire execution process to the derived class and allows the extending class to decide how the output is to be rendered. One good example of this is the DeclarativeWebScript class itself. It extends the AbstractWebScript class and provides a mechanism to render the response using FTL templates. In a scenario like streaming the content, there won't be any need for a response template; instead, the content itself needs to be rendered directly. In this case, the Java-backed controller class can extend from AbstractWebScript. If a web script has both a JavaScript-based controller and a Java-backed controller, then: If a Java-backed controller is derived from DeclarativeWebScript, then first the Java-backed controller will get executed and then the control would be passed to the JavaScript-backed controller prior to returning the model object to the response template. If the Java-backed controller is derived from AbstractWebScript, then, only the Java-backed controller will be executed. The JavaScript controller will not get executed. Summary In this article, we took a look at the reasons of using web scripts. Then we executed a web script from standalone Java program and move on to invoke a web script from Alfresco Share. Lastly, we saw the difference between DeclarativeWebScript versus AbstractWebScript. Resources for Article: Further resources on this subject: Alfresco 3 Business Solutions: Types of E-mail Integration [article] Alfresco 3: Writing and Executing Scripts [article] Overview of REST Concepts and Developing your First Web Script using Alfresco [article]
Read more
  • 0
  • 0
  • 12450
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-postmodel-workflow
Packt
04 Nov 2014
23 min read
Save for later

Postmodel Workflow

Packt
04 Nov 2014
23 min read
 This article written by Trent Hauck, the author of scikit-learn Cookbook, Packt Publishing, will cover the following recipes: K-fold cross validation Automatic cross validation Cross validation with ShuffleSplit Stratified k-fold Poor man's grid search Brute force grid search Using dummy estimators to compare results (For more resources related to this topic, see here.) Even though by design the articles are unordered, you could argue by virtue of the art of data science, we've saved the best for last. For the most part, each recipe within this article is applicable to the various models we've worked with. In some ways, you can think about this article as tuning the parameters and features. Ultimately, we need to choose some criteria to determine the "best" model. We'll use various measures to define best. Then in the Cross validation with ShuffleSplit recipe, we will randomize the evaluation across subsets of the data to help avoid overfitting. K-fold cross validation In this recipe, we'll create, quite possibly, the most important post-model validation exercise—cross validation. We'll talk about k-fold cross validation in this recipe. There are several varieties of cross validation, each with slightly different randomization schemes. K-fold is perhaps one of the most well-known randomization schemes. Getting ready We'll create some data and then fit a classifier on the different folds. It's probably worth mentioning that if you can keep a holdout set, then that would be best. For example, we have a dataset where N = 1000. If we hold out 200 data points, then use cross validation between the other 800 points to determine the best parameters. How to do it... First, we'll create some fake data, then we'll examine the parameters, and finally, we'll look at the size of the resulting dataset: >>> N = 1000>>> holdout = 200>>> from sklearn.datasets import make_regression>>> X, y = make_regression(1000, shuffle=True) Now that we have the data, let's hold out 200 points, and then go through the fold scheme like we normally would: >>> X_h, y_h = X[:holdout], y[:holdout]>>> X_t, y_t = X[holdout:], y[holdout:]>>> from sklearn.cross_validation import KFold K-fold gives us the option of choosing how many folds we want, if we want the values to be indices or Booleans, if want to shuffle the dataset, and finally, the random state (this is mainly for reproducibility). Indices will actually be removed in later versions. It's assumed to be True. Let's create the cross validation object: >>> kfold = KFold(len(y_t), n_folds=4) Now, we can iterate through the k-fold object: >>> output_string = "Fold: {}, N_train: {}, N_test: {}">>> for i, (train, test) in enumerate(kfold):       print output_string.format(i, len(y_t[train]),       len(y_t[test]))Fold: 0, N_train: 600, N_test: 200Fold: 1, N_train: 600, N_test: 200Fold: 2, N_train: 600, N_test: 200Fold: 3, N_train: 600, N_test: 200 Each iteration should return the same split size. How it works... It's probably clear, but k-fold works by iterating through the folds and holds out 1/n_folds * N, where N for us was len(y_t). From a Python perspective, the cross validation objects have an iterator that can be accessed by using the in operator. Often times, it's useful to write a wrapper around a cross validation object that will iterate a subset of the data. For example, we may have a dataset that has repeated measures for data points or we may have a dataset with patients and each patient having measures. We're going to mix it up and use pandas for this part: >>> import numpy as np>>> import pandas as pd>>> patients = np.repeat(np.arange(0, 100, dtype=np.int8), 8)>>> measurements = pd.DataFrame({'patient_id': patients,                   'ys': np.random.normal(0, 1, 800)}) Now that we have the data, we only want to hold out certain customers instead of data points: >>> custids = np.unique(measurements.patient_id)>>> customer_kfold = KFold(custids.size, n_folds=4)>>> output_string = "Fold: {}, N_train: {}, N_test: {}">>> for i, (train, test) in enumerate(customer_kfold):       train_cust_ids = custids[train]       training = measurements[measurements.patient_id.isin(                 train_cust_ids)]       testing = measurements[~measurements.patient_id.isin(                 train_cust_ids)]       print output_string.format(i, len(training), len(testing))Fold: 0, N_train: 600, N_test: 200Fold: 1, N_train: 600, N_test: 200Fold: 2, N_train: 600, N_test: 200Fold: 3, N_train: 600, N_test: 200 Automatic cross validation We've looked at the using cross validation iterators that scikit-learn comes with, but we can also use a helper function to perform cross validation for use automatically. This is similar to how other objects in scikit-learn are wrapped by helper functions, pipeline for instance. Getting ready First, we'll need to create a sample classifier; this can really be anything, a decision tree, a random forest, whatever. For us, it'll be a random forest. We'll then create a dataset and use the cross validation functions. How to do it... First import the ensemble module and we'll get started: >>> from sklearn import ensemble>>> rf = ensemble.RandomForestRegressor(max_features='auto') Okay, so now, let's create some regression data: >>> from sklearn import datasets>>> X, y = datasets.make_regression(10000, 10) Now that we have the data, we can import the cross_validation module and get access to the functions we'll use: >>> from sklearn import cross_validation>>> scores = cross_validation.cross_val_score(rf, X, y)>>> print scores[ 0.86823874 0.86763225 0.86986129] How it works... For the most part, this will delegate to the cross validation objects. One nice thing is that, the function will handle performing the cross validation in parallel. We can activate verbose mode play by play: >>> scores = cross_validation.cross_val_score(rf, X, y, verbose=3, cv=4)[CV] no parameters to be set[CV] no parameters to be set, score=0.872866 - 0.7s[CV] no parameters to be set[CV] no parameters to be set, score=0.873679 - 0.6s[CV] no parameters to be set[CV] no parameters to be set, score=0.878018 - 0.7s[CV] no parameters to be set[CV] no parameters to be set, score=0.871598 - 0.6s[Parallel(n_jobs=1)]: Done 1 jobs | elapsed: 0.7s[Parallel(n_jobs=1)]: Done 4 out of 4 | elapsed: 2.6s finished As we can see, during each iteration, we scored the function. We also get an idea of how long the model runs. It's also worth knowing that we can score our function predicated on which kind of model we're trying to fit. Cross validation with ShuffleSplit ShuffleSplit is one of the simplest cross validation techniques. This cross validation technique will simply take a sample of the data for the number of iterations specified. Getting ready ShuffleSplit is another cross validation technique that is very simple. We'll specify the total elements in the dataset, and it will take care of the rest. We'll walk through an example of estimating the mean of a univariate dataset. This is somewhat similar to resampling, but it'll illustrate one reason why we want to use cross validation while showing cross validation. How to do it... First, we need to create the dataset. We'll use NumPy to create a dataset, where we know the underlying mean. We'll sample half of the dataset to estimate the mean and see how close it is to the underlying mean: >>> import numpy as np>>> true_loc = 1000>>> true_scale = 10>>> N = 1000>>> dataset = np.random.normal(true_loc, true_scale, N)>>> import matplotlib.pyplot as plt>>> f, ax = plt.subplots(figsize=(7, 5))>>> ax.hist(dataset, color='k', alpha=.65, histtype='stepfilled');>>> ax.set_title("Histogram of dataset");>>> f.savefig("978-1-78398-948-5_06_06.png") NumPy will give the following output: Now, let's take the first half of the data and guess the mean: >>> from sklearn import cross_validation>>> holdout_set = dataset[:500]>>> fitting_set = dataset[500:]>>> estimate = fitting_set[:N/2].mean()>>> import matplotlib.pyplot as plt>>> f, ax = plt.subplots(figsize=(7, 5))>>> ax.set_title("True Mean vs Regular Estimate")>>> ax.vlines(true_loc, 0, 1, color='r', linestyles='-', lw=5,             alpha=.65, label='true mean')>>> ax.vlines(estimate, 0, 1, color='g', linestyles='-', lw=5,             alpha=.65, label='regular estimate')>>> ax.set_xlim(999, 1001)>>> ax.legend()>>> f.savefig("978-1-78398-948-5_06_07.png") We'll get the following output: Now, we can use ShuffleSplit to fit the estimator on several smaller datasets: >>> from sklearn.cross_validation import ShuffleSplit>>> shuffle_split = ShuffleSplit(len(fitting_set))>>> mean_p = []>>> for train, _ in shuffle_split:       mean_p.append(fitting_set[train].mean())       shuf_estimate = np.mean(mean_p)>>> import matplotlib.pyplot as plt>>> f, ax = plt.subplots(figsize=(7, 5))>>> ax.vlines(true_loc, 0, 1, color='r', linestyles='-', lw=5,             alpha=.65, label='true mean')>>> ax.vlines(estimate, 0, 1, color='g', linestyles='-', lw=5,             alpha=.65, label='regular estimate')>>> ax.vlines(shuf_estimate, 0, 1, color='b', linestyles='-', lw=5,             alpha=.65, label='shufflesplit estimate')>>> ax.set_title("All Estimates")>>> ax.set_xlim(999, 1001)>>> ax.legend(loc=3) The output will be as follows: As we can see, we got an estimate that was similar to what we expected, but we were able to take many samples to get that estimate. Stratified k-fold In this recipe, we'll quickly look at stratified k-fold valuation. We've walked through different recipes where the class representation was unbalanced in some manner. Stratified k-fold is nice because its scheme is specifically designed to maintain the class proportions. Getting ready We're going to create a small dataset. In this dataset, we will then use stratified k-fold validation. We want it small so that we can see the variation. For larger samples. it probably won't be as big of a deal. We'll then plot the class proportions at each step to illustrate how the class proportions are maintained: >>> from sklearn import datasets>>> X, y = datasets.make_classification(n_samples=int(1e3), weights=[1./11]) Let's check the overall class weight distribution: >>> y.mean()0.90300000000000002 Roughly, 90.5 percent of the samples are 1, with the balance 0. How to do it... Let's create a stratified k-fold object and iterate it through each fold. We'll measure the proportion of verse that are 1. After that we'll plot the proportion of classes by the split number to see how and if it changes. This code will hopefully illustrate how this is beneficial. We'll also plot this code against a basic ShuffleSplit: >>> from sklearn import cross_validation>>> n_folds = 50>>> strat_kfold = cross_validation.StratifiedKFold(y,                 n_folds=n_folds)>>> shuff_split = cross_validation.ShuffleSplit(n=len(y),                 n_iter=n_folds)>>> kfold_y_props = []>>> shuff_y_props = []>>> for (k_train, k_test), (s_train, s_test) in zip(strat_kfold,         shuff_split):        kfold_y_props.append(y[k_train].mean())       shuff_y_props.append(y[s_train].mean()) Now, let's plot the proportions over each fold: >>> import matplotlib.pyplot as plt>>> f, ax = plt.subplots(figsize=(7, 5))>>> ax.plot(range(n_folds), shuff_y_props, label="ShuffleSplit",           color='k')>>> ax.plot(range(n_folds), kfold_y_props, label="Stratified",           color='k', ls='--')>>> ax.set_title("Comparing class proportions.")>>> ax.legend(loc='best') The output will be as follows: We can see that the proportion of each fold for stratified k-fold is stable across folds. How it works... Stratified k-fold works by taking the y value. First, getting the overall proportion of the classes, then intelligently splitting the training and test set into the proportions. This will generalize to multiple labels: >>> import numpy as np>>> three_classes = np.random.choice([1,2,3], p=[.1, .4, .5],                   size=1000)>>> import itertools as it>>> for train, test in cross_validation.StratifiedKFold(three_classes, 5):       print np.bincount(three_classes[train])[ 0 90 314 395][ 0 90 314 395][ 0 90 314 395][ 0 91 315 395][ 0 91 315 396] As we can see, we got roughly the sample sizes of each class for our training and testing proportions. Poor man's grid search In this recipe, we're going to introduce grid search with basic Python, though we will use sklearn for the models and matplotlib for the visualization. Getting ready In this recipe, we will perform the following tasks: Design a basic search grid in the parameter space Iterate through the grid and check the loss/score function at each point in the parameter space for the dataset Choose the point in the parameter space that minimizes/maximizes the evaluation function Also, the model we'll fit is a basic decision tree classifier. Our parameter space will be 2 dimensional to help us with the visualization: The parameter space will then be the Cartesian product of the those two sets: We'll see in a bit how we can iterate through this space with itertools. Let's create the dataset and then get started: >>> from sklearn import datasets>>> X, y = datasets.make_classification(n_samples=2000, n_features=10) How to do it... Earlier we said that we'd use grid search to tune two parameters—criteria and max_features. We need to represent those as Python sets, and then use itertools product to iterate through them: >>> criteria = {'gini', 'entropy'}>>> max_features = {'auto', 'log2', None}>>> import itertools as it>>> parameter_space = it.product(criteria, max_features) Great! So now that we have the parameter space, let's iterate through it and check the accuracy of each model as specified by the parameters. Then, we'll store that accuracy so that we can compare different parameter spaces. We'll also use a test and train split of 50, 50: import numpy as nptrain_set = np.random.choice([True, False], size=len(y))from sklearn.tree import DecisionTreeClassifieraccuracies = {}for criterion, max_feature in parameter_space:   dt = DecisionTreeClassifier(criterion=criterion,         max_features=max_feature)   dt.fit(X[train_set], y[train_set])   accuracies[(criterion, max_feature)] = (dt.predict(X[~train_set])                                         == y[~train_set]).mean()>>> accuracies{('entropy', None): 0.974609375, ('entropy', 'auto'): 0.9736328125,('entropy', 'log2'): 0.962890625, ('gini', None): 0.9677734375, ('gini','auto'): 0.9638671875, ('gini', 'log2'): 0.96875} So we now have the accuracies and its performance. Let's visualize the performance: >>> from matplotlib import pyplot as plt>>> from matplotlib import cm>>> cmap = cm.RdBu_r>>> f, ax = plt.subplots(figsize=(7, 4))>>> ax.set_xticklabels([''] + list(criteria))>>> ax.set_yticklabels([''] + list(max_features))>>> plot_array = []>>> for max_feature in max_features:m = []>>> for criterion in criteria:       m.append(accuracies[(criterion, max_feature)])       plot_array.append(m)>>> colors = ax.matshow(plot_array, vmin=np.min(accuracies.values())             - 0.001, vmax=np.max(accuracies.values()) + 0.001,             cmap=cmap)>>> f.colorbar(colors) The following is the output: It's fairly easy to see which one performed best here. Hopefully, you can see how this process can be taken to the further stage with a brute force method. How it works... This works fairly simply, we just have to perform the following steps: Choose a set of parameters. Iterate through them and find the accuracy of each step. Find the best performer by visual inspection. Brute force grid search In this recipe, we'll do an exhaustive grid search through scikit-learn. This is basically the same thing we did in the previous recipe, but we'll utilize built-in methods. We'll also walk through an example of performing randomized optimization. This is an alternative to brute force search. Essentially, we're trading computer cycles to make sure that we search the entire space. We were fairly calm in the last recipe. However, you could imagine a model that has several steps, first imputation for fix missing data, then PCA reduce the dimensionality to classification. Your parameter space could get very large, very fast; therefore, it can be advantageous to only search a part of that space. Getting ready To get started, we'll need to perform the following steps: Create some classification data. We'll then create a LogisticRegression object that will be the model we're fitting. After that, we'll create the search objects, GridSearch and RandomizedSearchCV. How to do it... Run the following code to create some classification data: >>> from sklearn.datasets import make_classification>>> X, y = make_classification(1000, n_features=5) Now, we'll create our logistic regression object: >>> from sklearn.linear_model import LogisticRegression>>> lr = LogisticRegression(class_weight='auto') We need to specify the parameters we want to search. For GridSearch, we can just specify the ranges that we care about, but for RandomizedSearchCV, we'll need to actually specify the distribution over the same space from which to sample: >>> lr.fit(X, y)LogisticRegression(C=1.0, class_weight={0: 0.25, 1: 0.75},                   dual=False,fit_intercept=True,                  intercept_scaling=1, penalty='l2',                   random_state=None, tol=0.0001)>>> grid_search_params = {'penalty': ['l1', 'l2'],'C': [1, 2, 3, 4]} The only change we'll need to make is to describe the C parameter as a probability distribution. We'll keep it simple right now, though we will use scipy to describe the distribution: >>> import scipy.stats as st>>> import numpy as np>>> random_search_params = {'penalty': ['l1', 'l2'],'C': st.randint(1, 4)} How it works... Now, we'll fit the classifier. This works by passing lr to the parameter search objects: >>> from sklearn.grid_search import GridSearchCV, RandomizedSearchCV>>> gs = GridSearchCV(lr, grid_search_params) GridSearchCV implements the same API as the other models: >>> gs.fit(X, y)GridSearchCV(cv=None, estimator=LogisticRegression(C=1.0,             class_weight='auto', dual=False, fit_intercept=True,             intercept_scaling=1, penalty='l2', random_state=None,             tol=0.0001), fit_params={}, iid=True, loss_func=None,             n_jobs=1, param_grid={'penalty': ['l1', 'l2'], 'C':             [1, 2, 3, 4]}, pre_dispatch='2*n_jobs', refit=True,             score_func=None, scoring=None, verbose=0) As we can see with the param_grid parameter, our penalty and C are both arrays. To access the scores, we can use the grid_scores_ attribute of the grid search. We also want to find the optimal set of parameters. We can also look at the marginal performance of the grid search: >>> gs.grid_scores_[mean: 0.90300, std: 0.01192, params: {'penalty': 'l1', 'C': 1},mean: 0.90100, std: 0.01258, params: {'penalty': 'l2', 'C': 1},mean: 0.90200, std: 0.01117, params: {'penalty': 'l1', 'C': 2},mean: 0.90100, std: 0.01258, params: {'penalty': 'l2', 'C': 2},mean: 0.90200, std: 0.01117, params: {'penalty': 'l1', 'C': 3},mean: 0.90100, std: 0.01258, params: {'penalty': 'l2', 'C': 3},mean: 0.90100, std: 0.01258, params: {'penalty': 'l1', 'C': 4},mean: 0.90100, std: 0.01258, params: {'penalty': 'l2', 'C': 4}] We might want to get the max score: >>> gs.grid_scores_[1][1]0.90100000000000002>>> max(gs.grid_scores_, key=lambda x: x[1])mean: 0.90300, std: 0.01192, params: {'penalty': 'l1', 'C': 1} The parameters obtained are the best choices for our logistic regression. Using dummy estimators to compare results This recipe is about creating fake estimators; this isn't the pretty or exciting stuff, but it is worthwhile to have a reference point for the model you'll eventually build. Getting ready In this recipe, we'll perform the following tasks: Create some data random data. Fit the various dummy estimators. We'll perform these two steps for regression data and classification data. How to do it... First, we'll create the random data: >>> from sklearn.datasets import make_regression, make_classification# classification if for later>>> X, y = make_regression()>>> from sklearn import dummy>>> dumdum = dummy.DummyRegressor()>>> dumdum.fit(X, y)DummyRegressor(constant=None, strategy='mean') By default, the estimator will predict by just taking the mean of the values and predicting the mean values: >>> dumdum.predict(X)[:5]array([ 2.23297907, 2.23297907, 2.23297907, 2.23297907, 2.23297907]) There are other two other strategies we can try. We can predict a supplied constant (refer to constant=None from the preceding command). We can also predict the median value. Supplying a constant will only be considered if strategy is "constant". Let's have a look: >>> predictors = [("mean", None),                 ("median", None),                 ("constant", 10)]>>> for strategy, constant in predictors:       dumdum = dummy.DummyRegressor(strategy=strategy,                 constant=constant)>>> dumdum.fit(X, y)>>> print "strategy: {}".format(strategy), ",".join(map(str,         dumdum.predict(X)[:5]))strategy: mean 2.23297906733,2.23297906733,2.23297906733,2.23297906733,2.23297906733strategy: median 20.38535248,20.38535248,20.38535248,20.38535248,20.38535248strategy: constant 10.0,10.0,10.0,10.0,10.0 We actually have four options for classifiers. These strategies are similar to the continuous case, it's just slanted toward classification problems: >>> predictors = [("constant", 0),                 ("stratified", None),                 ("uniform", None),                 ("most_frequent", None)] We'll also need to create some classification data: >>> X, y = make_classification()>>> for strategy, constant in predictors:       dumdum = dummy.DummyClassifier(strategy=strategy,                 constant=constant)       dumdum.fit(X, y)       print "strategy: {}".format(strategy), ",".join(map(str,             dumdum.predict(X)[:5]))strategy: constant 0,0,0,0,0strategy: stratified 1,0,0,1,0strategy: uniform 0,0,0,1,1strategy: most_frequent 1,1,1,1,1 How it works... It's always good to test your models against the simplest models and that's exactly what the dummy estimators give you. For example, imagine a fraud model. In this model, only 5 percent of the data set is fraud. Therefore, we can probably fit a pretty good model just by never guessing any fraud. We can create this model by using the stratified strategy, using the following command. We can also get a good example of why class imbalance causes problems: >>> X, y = make_classification(20000, weights=[.95, .05])>>> dumdum = dummy.DummyClassifier(strategy='most_frequent')>>> dumdum.fit(X, y)DummyClassifier(constant=None, random_state=None, strategy='most_frequent')>>> from sklearn.metrics import accuracy_score>>> print accuracy_score(y, dumdum.predict(X))0.94575 We were actually correct very often, but that's not the point. The point is that this is our baseline. If we cannot create a model for fraud that is more accurate than this, then it isn't worth our time. Summary This article taught us how we can take a basic model produced from one of the recipes and tune it so that we can achieve better results than we could with the basic model. Resources for Article: Further resources on this subject: Specialized Machine Learning Topics [article] Machine Learning in IPython with scikit-learn [article] Our First Machine Learning Method – Linear Classification [article]
Read more
  • 0
  • 0
  • 2245

article-image-getting-ready-launch-your-phonegap-app-real-world
Packt
31 Oct 2014
7 min read
Save for later

Getting Ready to Launch Your PhoneGap App in the Real World

Packt
31 Oct 2014
7 min read
In this article by Yuxian, Eugene Liang, author of PhoneGap and AngularJS for Cross-platform Development, we will run through some of the stuff that you should be doing before launching your app to the world, whether it's through Apple App Store or Google Android Play Store. (For more resources related to this topic, see here.) Using phonegap.com The services on https://build.phonegap.com/ are a straightforward way for you to get your app compiled for various devices. While this is a paid service, there is a free plan if you only have one app that you want to work on. This would be fine in our case. Choose a plan from PhoneGap You will need to have an Adobe ID in order to use PhoneGap services. If not, feel free to create one. Since the process for generating compiled apps from PhoneGap may change, it's best that you visit https://build.phonegap.com/ and sign up for their services and follow their instructions. Preparing your PhoneGap app for an Android release This section generally focuses on things that are specific for the Android platform. This is by no means a comprehensive checklist, but has some of the common tasks that you should go through before releasing your app to the Android world. Testing your app on real devices It is always good to run your app on an actual handset to see how the app is working. To run your PhoneGap app on a real device, issue the following command after you plug your handset into your computer: cordova run android You will see that your app now runs on your handset. Exporting your app to install on other devices In the previous section we talked about installing your app on your device. What if you want to export the APK so that you can test the app on other devices? Here's what you can do: As usual, build your app using cordova build android Alternatively, if you can, run cordova build release The previous step will create an unsigned release APK at /path_to_your_project/platforms/android/ant-build. This app is called YourAppName-release-unsigned.apk. Now, you can simply copy YourAppName-release-unsigned.apk and install it on any android based device you want. Preparing promotional artwork for release In general, you will need to include screenshots of your app for upload to Google Play. In case your device does not allow you to take screenshots, here's what you can do: The first technique that you can use is to simply run your app in the emulator and take screenshots off it. The size of the screenshot may be substantially larger, so you can crop it using GIMP or some other online image resizer. Alternatively, use the web app version and open it in your Google Chrome Browser. Resize your browser window so that it is narrow enough to resemble the width of mobile devices. Building your app for release To build your app for release, you will need Eclipse IDE. To start your Eclipse IDE, navigate to File | New | Project. Next, navigate to Existing Code | Android | Android Project. Click on Browse and select the root directory of your app. The Project to Import window should show platforms/android. Now, select Copy projects into workspace if you want and then click on Finish. Signing the app We have previously exported the app (unsigned) so that we can test it on devices other than those plugged into our computer. However, to release your app to the Play Store, you need to sign them with keys. The steps here are the general steps that you need to follow in order to generate "signed" APK apps to upload your app to the Play Store. Right-click on the project that you have imported in the previous section, and then navigate to Android Tools | Export Signed Application Package. You will see the Project Checks dialog. In the Project Checks dialog, you will see if your project has any errors or not. Next, you should see the Keystore selection dialog. You will now create the key using the app name (without space) and the extension .keystore. Since this app is the first version, there is no prior original name to use. Now, you can browse to the location and save the keystore, and in the same box, give the name of the keystore. In the Keystore election dialog, add your desired password twice and click on Next. You will now see the Key Creation dialog. In the Key Creation dialog, use app_name as your alias (without any spaces) and give the password of your keystore. Feel free to enter 50 for validity (which means the password is valid for 50 years). The remaining fields such as names, organization, and so on are pretty straightforward, so you can just go ahead and fill them in. Finally, select the Destination APK file, which is the location to which you will export your .apk file. Bear in mind that the preceding steps are not a comprehensive list of instructions. For the official documentation, feel free to visit http://developer.android.com/tools/publishing/app-signing.html. Now that we are done with Android, it's time to prepare our app for iOS. iOS As you might already know, preparing your PhoneGap app for Apple App Store requires similar levels, if not more, as compared to your usual Android deployment. In this section, I will not be covering things like making sure your app is in tandem with Apple User Interface guidelines, but rather, how to improve your app before it reaches the App Store. Before we get started, there are some basic requirements: Apple Developer Membership (if you ultimately want to deploy to the App Store) Xcode Running your app on an iOS device If you already have an iOS device, all you need to do is to plug your iOS device to your computer and issue the following command: cordova run ios You should see that your PhoneGap app will build and launch on your device. Note that before running the preceding command, you will need to install the ios-deploy package. You can install it using the following command: sudo npm install –g ios-deploy Other techniques There are other ways to test and deploy your apps. These methods can be useful if you want to deploy your app to your own devices or even for external device testing. Using Xcode Now let's get started with Xcode: After starting your project using the command-line tool and after adding in iOS platform support, you may actually start developing using Xcode. You can start your Xcode and click on Open Other, as shown in the following screenshot: Once you have clicked on Open Other, you will need to browse to your ToDo app folder. Drill down until you see ToDo.xcodeproj (navigate to platforms | ios). Select and open this file. You will see your Xcode device importing the files. After it's all done, you should see something like the following screenshot: Files imported into Xcode Notice that all the files are now imported to your Xcode, and you can start working from here. You can also deploy your app either to devices or simulators: Deploy on your device or on simulators Summary In this article, we went through the basics of packaging your app before submission to the respective app stores. In general, you should have a good idea of how to develop AngularJS apps and apply mobile skins on them so that it can be used on PhoneGap. You should also notice that developing for PhoneGap apps typically takes the pattern of creating a web app first, before converting it to a PhoneGap version. Of course, you may structure your project so that you can build a PhoneGap version from day one, but it may make testing more difficult. Anyway, I hope that you enjoyed this article and feel free to follow me at http://www.liangeugene.com and http://growthsnippets.com. Resources for Article: Further resources on this subject: Using Location Data with PhoneGap [Article] Working with the sharing plugin [Article] Geolocation – using PhoneGap features to improve an app's functionality, write once use everywhere [Article]
Read more
  • 0
  • 0
  • 6563

article-image-creating-our-first-animation-angularjs
Packt
31 Oct 2014
36 min read
Save for later

Creating Our First Animation in AngularJS

Packt
31 Oct 2014
36 min read
In this article by Richard Keller, author of the book Learning AngularJS Animations, we will learn how to apply CSS animations within the context of AngularJS by creating animations using CSS transitions and CSS keyframe animations that are integrated with AngularJS native directives using the ngAnimate module. In this article, we will learn: The ngAnimate module setup and usage AngularJS directives with support for out-of-the-box animation AngularJS animations with the CSS transition AngularJS animations with CSS keyframe animations The naming convention of the CSS animation classes Animation of the ngMessage and ngMessages directives (For more resources related to this topic, see here.) The ngAnimate module setup and usage AngularJS is a module-based framework; if we want our AngularJS application to have the animation feature, we need to add the animation module (ngAnimate). We have to include this module in the application by adding the module as a dependency in our AngularJS application. However, before that, we should include the JavaScript angular-animate.js file in HTML. Both files are available on the Google content distribution network (CDN), Bower, Google Code, and https://angularjs.org/. The Google developers' CDN hosts many versions of AngularJS, as listed here: https://developers.google.com/speed/libraries/devguide#angularjs Currently, AngularJS Version 1.3 is the latest stable version, so we will use AngularJS Version 1.3.0 on all samples files of this book; we can get them from https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.min.js and https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular-animate.min.js. You might want to use Bower. To do so, check out this great video article at https://thinkster.io/egghead/intro-to-bower/, explaining how to use Bower to get AngularJS. We include the JavaScript files of AngularJS and the ngAnimate module, and then we include the ngAnimate module as a dependency of our app. This is shown in the following sample, using the Google CDN and the minified versions of both files: <!DOCTYPE html> <html ng-app"myApp"> <head> <title>AngularJS animation installation</title> </head> <body> <script src="//ajax.googleapis.com/ajax/libs/angularjs/    1.3.0/angular.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs/    1.3.0/angular-animate.min.js"></script> <script>    var app = angular.module('myApp', ['ngAnimate']); </script> </body> </html> Here, we already have an AngularJS web app configured to use animations. Now, we will learn how to animate using AngularJS directives. AngularJS directives with native support for animations AngularJS has the purpose of changing the way web developers and designers manipulate the Document Object Model (DOM). We don't directly manipulate the DOM when developing controllers, services, and templates. AngularJS does all the DOM manipulation work for us. The only place where an application touches the DOM is within directives. For most of the DOM manipulation requirements, AngularJS already provides are built-in directives that fit our needs. There are many important AngularJS directives that already have built-in support for animations, and they use the ngAnimate module. This is why this module is so useful; it allows us to use animations within AngularJS directives DOM manipulation. This way, we don't have to replicate native directives by extending them just to add animation functionality. The ngAnimate module provides us a way to hook animations in between AngularJS directives execution. It even allows us to hook on custom directives. As we are dealing with animations between DOM manipulations, we can have animations before and after an element is added to or removed from the DOM, after an element changes (by adding or removing classes), and before and after an element is moved in the DOM. These events are the moments when we might add animations. Fade animations using AngularJS Now that we already know how to install a web app with the ngAnimate module enabled, let's create fade-in and fade-out animations to get started with AngularJS animations. We will use the same HTML from the installation topic and add a simple controller, just to change an ngShow directive model value and add a CSS transition. The ngShow directive shows or hides the given element based on the expression provided to the ng-show attribute. For this sample, we have a Toggle fade button that changes the ngShow model value, so we can see what happens when the element fades in and fades out from the DOM. The ngShow directive shows and hides an element by adding and removing the ng-hide class from the element that contains the directive, shown as follows: <!DOCTYPE html> <html ng-app="myApp"> <head> <title>AngularJS animation installation</title> </head> <body> <style type="text/css">    .firstSampleAnimation.ng-hide-add,    .firstSampleAnimation.ng-hide-remove {     -webkit-transition: 1s ease-in-out opacity;     transition: 1s ease-in-out opacity;     opacity: 1;  } .firstSampleAnimation.ng-hide { opacity: 0; } </style> <div> <div ng-controller="animationsCtrl"> <h1>ngShow animation</h1> <button ng-click="fadeAnimation = !fadeAnimation">Toggle fade</button> fadeAnimation value: {{fadeAnimation}} <div class="firstSampleAnimation" ng-show="fadeAnimation"> This element appears when the fadeAnimation model is true </div> </div> </div> <script src="//ajax.googleapis.com/ajax/libs/angularjs/ 1.3.0/angular.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs/ 1.3.0/angular-animate.min.js"></script> <script> var app = angular.module('myApp', ['ngAnimate']); app.controller('animationsCtrl', function ($scope) { $scope.fadeAnimation = false; }); </script> </body> </html> In the CSS code, we declared an opacity transition to elements with the firstAnimationSample and ng-hide-add classes, or elements with the firstAnimationSample and ng-hide-remove classes. We also added the firstAnimationSample class to the same element that has the ng-show directive attribute. The fadeAnimation model is initially false, so the element with the ngShow directive is initially hidden, as the ngShow directive adds the ng-hide class to the element to set the display property as none. When we first click on the Toggle fade button, the fadeAnimation model will become true. Then, the ngShow directive will remove the ng-hide class to display the element. But before that, the ngAnimate module knows there is a transition declared for this element. Because of that, the ngAnimate module will append the ng-hide-remove class to trigger the hide animation start. Then, ngAnimate will add the ng-hide-remove-active class that can contain the final state of the animation to the element and remove the ng-hide class at the same time. Both classes will last until the animation (1 second in this sample) finishes, and then they are removed. This is the fade-in animation; ngAnimate triggers animations by adding and removing the classes that contain the animations; this is why we say that AngularJS animations are class based. This is where the magic happens. All that we did to create this fade-in animation was declare a CSS transition with the class name, ng-hide-remove. This class name means that it's appended when the ng-hide class is removed. The fade-out animation will happen when we click on the Toggle fade button again, and then, the fadeAnimation model will become false. The ngShow directive will add the ng-hide class to remove the element, but before this, the ngAnimate module knows that there is a transition declared for that element too. The ngAnimate module will append the ng-hide-add class and then add the ng-hide and ng-hide-add-active classes to the element at the same time. Both classes will last until the animation (1 second in this sample) finishes, then they are removed, and only the ng-hide class is kept, to hide the element. The fade-out animation was created by just declaring the CSS transition with the class name of ng-hide-add. It is easy to understand that this class is appended to the element when the ng-hide class is about to be added. The AngularJS animations convention As this article is intended to teach you how to create animations with AngularJS, you need to know which directives already have built-in support for AngularJS animations to make our life easier. Here, we have a table of directives with the directive names and the events of the directive life cycle when animation hooks are supported. The first row means that the ngRepeat directive supports animation on enter, leave, and move event times. All events are relative to DOM manipulations, for example, when an element enters or leaves DOM, or when a class is added to or removed from an element. Directive Supported animations ngRepeat Enter, leave, and move ngView Enter and leave ngInclude Enter and leave ngSwitch Enter and leave ngIf Enter and leave ngClass Add and remove ngShow and ngHide Add and remove form and ngModel Add and remove ngMessages Add and remove ngMessage Enter and leave Perhaps, the more experienced AngularJS users have noticed that the most frequently used directives are attended in this list. This is great; it means that animating with AngularJS isn't hard for most use cases. AngularJS animation with CSS transitions We need to know how to bind the CSS animation as well as the AngularJS directives listed in the previous table. The ngIf directive, for example, has support for the enter and leave animations. When the value of the ngIf model is changed to true, it triggers the animation by adding the ng-enter class to the element just after the ngIf DOM element is created and injected. This triggers the animation, and the classes are kept for the duration of the transition ends. Then, the ng-enter class is removed. When the value of ngIf is changed to false, the ng-leave class is added to the element just before the ngIf content is removed from the DOM, and so, the animation is triggered while the element still exists. To illustrate the AngularJS ngIf directive and ngAnimate module behavior, let's see what happens in a sample. First, we have to declare a button that toggles the value of the fadeAnimation model, and one div tag that uses ng-if="fadeAnimation", so we can see what happens when the element is removed and added back. Here, we create the HTML code using the HTML template we used in the last topic to install the ngAnimate module: <!DOCTYPE html> <html ng-app="myApp"> <head> <title>AngularJS ngIf sample</title> </head> <body> <style> /* ngIf animation */ .animationIf.ng-enter, .animationIf.ng-leave { -webkit-transition: opacity ease-in-out 1s; transition: opacity ease-in-out 1s; } .animationIf.ng-enter, .animationIf.ng-leave.ng-leave-active { opacity: 0; } .animationIf.ng-leave, .animationIf.ng-enter.ng-enter-active { opacity: 1; } </style> <div ng-controller="animationsCtrl"> <h1>ngIf animation</h1> <div> fadeAnimation value: {{fadeAnimation}} </div> <button ng-click="fadeAnimation = !fadeAnimation"> Toggle fade</button> <div ng-if="fadeAnimation" class="animationIf"> This element appears when the fadeAnimation model is true </div> </div> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular-animate.min.js"></script> <script> var app = angular.module('myApp', ['ngAnimate']); app.controller('animationsCtrl', function ($scope) { $scope.fadeAnimation = false; }); </script> </body> </html> So, let's see what happens in the DOM just after we click on the Toggle fade button. We will use Chrome Developer Tools (Chrome DevTools) to check the HTML in each animation step. It's a native tool that comes with the Chrome browser. To open Chrome DevTools, you just need to right-click on any part of the page and click on Inspect Element. The ng-enter class Our CSS declaration added an animation to the element with the animationIf and ng-enter classes. So, the transition is applied when the element has the ng-enter class too. This class is appended to the element when the element has just entered the DOM. It's important to add the specific class of the element you want to animate in the selector, which in this case is the animationIf class, because many other elements might trigger animation and add the ng-enter class too. We should be careful to use the specific target element class. Until the animation is completed, the resulting HTML fragment will be as follows: Consider the following snippet: <div ng-if="fadeAnimation" class="animationIf ng-scope ng-animate ng-enter ng-enter-active"> fadeAnimation value: true </div> We can see that the ng-animate, ng-enter, and ng-enter-active classes were added to the element. After the animation is completed, the DOM will have the animation classes removed as the next screenshot shows: As you can see, the animation classes are removed: <div ng-if="fadeAnimation" class="animationIf ng-scope"> This element appears when the fadeAnimation model is true </div> The ng-leave class We added the same transition of the ng-enter class to the element with the animationIf and ng-leave classes. The ng-leave class is added to the element before the element leaves the DOM. So, before the element vanishes, it will display the fade effect too. If we click again on the Toggle fade button, the leave animation will be displayed and the following HTML fragment and screen will be rendered: The fragment rendered is as follows: <div ng-if="fadeAnimation" class="animationIf ng-scope g-animate ng-leave ng-leave-active"> This element appears when the fadeAnimation model is true </div> We can notice that the ng-animate, ng-leave, and ng-leave-active classes were added to the element. Finally, after the element is removed from the DOM, the rendered result will be as follows: The code after removing the element is as follows: <div ng-controller="animationsCtrl" class="ng-scope"> <div class="ng-binding"> fadeAnimation value: false </div> <button ng-click="fadeAnimation = !fadeAnimation"> Toggle fade</button> <!-- ngIf: fadeAnimation --> </div> Furthermore, there are the ng-enter-active and ng-leave-active classes. They are appended to the element classes too. Both are used to define the target value of the transition, and the -active classes define the destination CSS so that we can create a transition between the start and the end of an event. For example, ng-enter is the initial class of the enter event and ng-enter-active is the final class of the enter event. They are used to determine the style applied at the start of the animation beginning and the final transition style, and they are displayed when the transition completes the cycle. A use case of the -active class is when we want to set an initial color and a final color using the CSS transition. In the last sample case, the ng-leave class has opacity set to 1 and the ng-leave-active class has the opacity set to 0; so, the element will fade away at the end of the animation. Great, we just created our first animation using AngularJS and CSS transitions. AngularJS animation with CSS keyframe animations We created an animation using the ngIf directive and CSS transitions. Now we are going to create an animation using ngRepeat and CSS animations (keyframes). As we saw in the earlier table on directives and the supported animation events, the ngRepeat directive supports animation on the enter, leave, and move events. We already used the enter and leave events in the last sample. The move event is triggered when an item is moved around on the list of items. For this sample, we will create three functions on the controller scope: one to add elements to the list in order to execute the enter event, one to remove an item from list in order to execute the leave event, and one to sort the elements so that we can see the move event. Here is the JavaScript with the functions; $scope.items is the array that we will use on the ngRepeat directive: var app = angular.module('myApp', ['ngAnimate']); app.controller('animationsCtrl', function ($scope) { $scope.items = [{ name: 'Richard' }, { name: 'Bruno' } , { name: 'Jobson' }]; $scope.counter = 0; $scope.addItem = function () { var name = 'Item' + $scope.counter++; $scope.items.push({ name: name }); }; $scope.removeItem = function () { var length = $scope.items.length; var indexRemoved = Math.floor(Math.random() * length); $scope.items.splice(indexRemoved, 1); }; $scope.sortItems = function () { $scope.items.sort(function (a, b) { return a[name] < b[name] ? -1 : 1 }); }; }); The HTML is as follows; it is without the CSS styles because we will see them later separating each animation block: <!DOCTYPE html> <html ng-app="myApp"> <head> <title>AngularJS ngRepeat sample</title> </head> <body> <div ng-controller="animationsCtrl"> <h1>ngRepeat Animation</h1> <div> <div ng-repeat="item in items" class="repeatItem"> {{item.name}} </div> <button ng-click="addItem()">Add item</button> <button ng-click="removeItem()">Remove item</button><button ng-click="sortItems()"> Sort items</button> </div> </div> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular-animate.min.js"></script> </body> </html> We will add an animation to the element with the repeatItem and ng-enter classes, and we will declare the from and to keyframes. So, when an element appears, it starts with opacity set to 0 and color set as red and will animate for 1 second until opacity is 1 and color is black. This will be seen when an item is added to the ngRepeat array. The enter animation definition is declared as follows: /* ngRepeat ng-enter animation */ .repeatItem.ng-enter { -webkit-animation: 1s ng-enter-repeat-animation; animation: 1s ng-enter-repeat-animation; } @-webkit-keyframes ng-enter-repeat-animation { from { opacity: 0; color: red; } to { opacity: 1; color: black; } } @keyframes ng-enter-repeat-animation { from { opacity: 0; color: red; } to { opacity: 1; color: black; } } The move animation is declared next is to be triggered when we move an item of ngRepeat. We will add a keyframe animation to the element with the repeatItem and ng-move classes. We will declare the from and to keyframes. So, when an element moves, it starts with opacity set to 0 and color set as black and will animate for 1 second until opacity is 0.5 and color is blue, shown as follows: /* ngRepeat ng-move animation */ .repeatItem.ng-move { -webkit-animation: 1s ng-move-repeat-animation; animation: 1s ng-move-repeat-animation; } @-webkit-keyframes ng-move-repeat-animation { from { opacity: 1; color: black; } to { opacity: 0.5; color: blue; } } @keyframes ng-move-repeat-animation { from { opacity: 1; color: black; } to { opacity: 0.5; color: blue; } } The leave animation is declared next and is to be triggered when we remove an item of ngRepeat. We will add a keyframe animation to the element with the repeatItem and ng-leave classes; we will declare the from and to keyframes; so, when an element leaves the DOM, it starts with opacity set to 1 and color set as black and animates for 1 second until opacity is 0 and color is red, shown as follows: /* ngRepeat ng-leave animation */ .repeatItem.ng-leave { -webkit-animation: 1s ng-leave-repeat-animation; animation: 1s ng-leave-repeat-animation; } @-webkit-keyframes ng-leave-repeat-animation { from { opacity: 1; color: black; } to { opacity: 0; color: red; } } @keyframes ng-leave-repeat-animation { from { opacity: 1; color: black; } to { opacity: 0; color: red; } } We can see that the ng-enter-active and ng-leave-active classes aren't used on this sample, as the keyframe animation already determines the initial and final properties' states. In this case, as we used CSS keyframes, the classes with the -active suffix are useless, although for CSS transitions, it's useful to set an animation destination. The CSS naming convention In the last few sections, we saw how to create animations using AngularJS, CSS transitions, and CSS keyframe animations. Creating animations using both CSS transitions and CSS animations is very similar because all animations in AngularJS are class based, and AngularJS animations have a well-defined class name pattern. We must follow the CSS naming convention by adding a specific class to the directive element so that we can determine the element animation. Otherwise, the ngAnimate module will not be able to recognize which element the animation applies to. We already know that both ngIf and ngRepeat use the ng-enter, ng-enter-active, ng-leave, and ng-leave-active classes that are added to the element in the enter and leave events. It's the same naming convention used by the ngInclude, ngSwitch, ngMessage, and ngView directives. The ngHide and ngShow directives follow a different convention. They add the ng-hide-add and ng-hide-add-active classes when the element is going to be hidden. When the element is going to be shown, they add the ng-hide-remove and ng-hide-remove-active classes. These class names are more intuitive for the purpose of hiding and showing elements. There is also the ngClass directive convention that uses the class name added to create the animation classes with the -add, -add-active, -remove, and -remove-active suffixes, similar to the ngHide directive. The ngRepeat directive uses the ng-move and ng-move-active classes when elements move their position in the DOM, as we already saw in the last sample. The ngClass directive animation sample The ngClass directive allows us to dynamically set CSS classes. So, we can programmatically add and remove CSS from DOM elements. Classes are already used to change element styles, so it's very good to see how useful animating the ngClass directive is. Let's see a sample of ngClass so that it's easier to understand. We will create the HTML code with a Toggle ngClassbutton that will add and remove the animationClass class from the element with the initialClass class through the ngClass directive: <!DOCTYPE html> <html ng-app="myApp"> <head> <title>AngularJS ngClass sample</title> </head> <body> <link href="ngClassSample.css" rel="stylesheet" /> <div> <h1>ngClass Animation</h1> <div> <button ng-click="toggleNgClass = !toggleNgClass">Toggle ngClass</button> <div class="initialClass" ng-class=" {'animationClass' : toggleNgClass}"> This element has class 'initialClass' and the ngClass directive is declared as ng-class="{'animationClass' : toggleNgClass}" </div> </div> </div> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular-animate.min.js"></script> <script> var app = angular.module('myApp', ['ngAnimate']); </script> </body> </html> For this sample, we will use two basic classes: an initial class and the class that the ngClass directive will add to and remove from the element: /* ngclass animation */ /*This is the initialClass, that keeps in the element*/ .initialClass { background-color: white; color: black; border: 1px solid black; } /* This is the animationClass, that is added or removed by the ngClass expression*/ .animationClass { background-color: black; color: white; border: 1px solid white; } To create the animation, we will define a CSS animation using keyframes; so, we only will need to use the animationClass-add and animationClass-remove classes to add animations: @-webkit-keyframes ng-class-animation { from { background-color: white; color:black; border: 1px solid black; } to { background-color: black; color: white; border: 1px solid white; } } @keyframes ng-class-animation { from { background-color: white; color:black; border: 1px solid black; } to { background-color: black; color: white; border: 1px solid white; } } The initial state is shown as follows: So, we want to display an animation when animationClass is added to the element with the initialClass class by the ngClass directive. This way, our animation selector will be: .initialClass.animationClass-add{ -webkit-animation: 1s ng-class-animation; animation: 1s ng-class-animation; } After 500 ms, the result should be a complete gray div tag because the text, border, and background colors are halfway through the transition between black and white, as we can see in this screenshot: After a second of animation, this is the result: The remove animation, which occurs when animationClass is removed, is similar to the enter animation. However, this animation should be the reverse of the enter animation, and so, the CSS selector of the animation will be: initialClass.animationClass-remove { -webkit-animation: 1s ng-class-animation reverse; animation: 1s ng-class-animation reverse; } The animation result will be the same as we saw in previous screenshots, but in the reverse order. The ngHide and ngShow animation sample Let's see one sample of the ngHide animation, which is the directive that shows and hides the given HTML code based on an expression, such as the ngShow directive. We will use this directive to create a success notification message that fades in and out. To have a lean CSS file in this sample, we will use the Bootstrap CSS library, which is a great library to use with AngularJS. There is an AngularJS version of this library created by the Angular UI team, available at http://angular-ui.github.io/bootstrap/. The Twitter Bootstrap library is available at http://getbootstrap.com/. For this sample, we will use the Microsoft CDN; you can check out the Microsoft CDN libraries at http://www.asp.net/ajax/cdn. Consider the following HTML: <!DOCTYPE html> <html ng-app="myApp"> <head> <title>AngularJS ngHide sample</title> </head> <body> <link href="http://ajax.aspnetcdn.com/ajax/bootstrap/3.2.0/css/ bootstrap.css" rel="stylesheet" /> <style> /* ngHide animation */ .ngHideSample { padding: 10px; } .ngHideSample.ng-hide-add { -webkit-transition: all linear 0.3s; -moz-transition: all linear 0.3s; -ms-transition: all linear 0.3s; -o-transition: all linear 0.3s; opacity: 1; } .ngHideSample.ng-hide-add-active { opacity: 0; } .ngHideSample.ng-hide-remove { -webkit-transition: all linear 0.3s; -moz-transition: all linear 0.3s; -ms-transition: all linear 0.3s; -o-transition: all linear 0.3s; opacity: 0; } .ngHideSample.ng-hide-remove-active { opacity: 1; } </style> <div> <h1>ngHide animation</h1> <div> <button ng-click="disabled = !disabled">Toggle ngHide animation</button> <div ng-hide="disabled" class="ngHideSample bg-success"> This element has the ng-hide directive. </div> </div> </div> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular-animate.min.js"></script> <script> var app = angular.module('myApp', ['ngAnimate']); </script> </body> </html> In this sample, we created an animation in which when the element is going to hide, its opacity is transitioned until it's set to 0. Also, when the element appears again, its opacity transitions back to 1 as we can see in the sequence of the following sequence of screenshots. In the initial state, the output is as follows: After we click on the button, the notification message starts to fade: After the add (ng-hide-add) animation has completed, the output is as follows: Then, if we toggle again, we will see the success message fading in: After the animation has completed, it returns to the initial state: The ngShow directive uses the same convention; the only difference is that each directive has the opposite behavior for the model value. When the model is true, ngShow removes the ng-hide class and ngHide adds the ng-hide class, as we saw in the first sample of this article. The ngModel directive and form animations We can easily animate form controls such as input, select, and textarea on ngModel changes. Form controls already work with validation CSS classes such as ng-valid, ng-invalid, ng-dirty, and ng-pristine. These classes are appended to form controls by AngularJS, based on validations and the current form control status. We are able to animate on the add and remove features of those classes. So, let's see an example of how to change the input color to red when a field becomes invalid. This helps users to check for errors while filling in the form before it is submitted. The animation eases the validation error experience. For this sample, a valid input will contain only digits and will become invalid once a character is entered. Consider the following HTML: <h1>ngModel and form animation</h1> <div> <form> <input ng-model="ngModelSample" ng-pattern="/^d+$/" class="inputSample" /> </form> </div> This ng-pattern directive validates using the regular expression if the model ngModelSample is a number. So, if we want to warn the user when the input is invalid, we will set the input text color to red using a CSS transition. Consider the following CSS: /* ngModel animation */ .inputSample.ng-invalid-add { -webkit-transition: 1s linear all; transition: 1s linear all; color: black; } .inputSample.ng-invalid { color: red; } .inputSample.ng-invalid-add-active { color: red; } We followed the same pattern as ngClass. So, when the ng-invalid class is added, it will append the ng-invalid-add class and the transition will change the text color to red in a second; it will then continue to be red, as we have defined the ng-invalid color as red too. The test is easy; we just need to type in one non-numeric character on the input and it will display the animation. The ngMessage and ngMessages directive animations Both the ngMessage and ngMessages directives are complimentary, but you can choose which one you want to animate, or even animate both of them. They became separated from the core module, so we have to add the ngMessages module as a dependency of our AngularJS application. These directives were added to AngularJS in Version 1.3, and they are useful to display messages based on the state of the model of a form control. So, we can easily display a custom message if an input has a specific validation error, for example, when the input is required but is not filled in yet. Without these directives, we would rely on JavaScript code and/or complex ngIf statements to accomplish the same result. For this sample, we will create three different error messages for three different validations of a password field, as described in the following HTML: <!DOCTYPE html> <html ng-app="myApp"> <head> <title>ngMessages animation</title> </head> <body> <link href="ngMessageAnimation.css" rel="stylesheet" /> <h1>ngMessage and ngMessages animation</h1> <div> <form name="messageAnimationForm"> <label for="modelSample">Password validation input</label> <div> <input ng-model="ngModelSample" id="modelSample" name="modelSample" type="password" ng-pattern= "/^d+$/" ng-minlength="5" ng-maxlength="10" required class="ngMessageSample" /> <div ng-messages="messageAnimationForm. modelSample.$error" class="ngMessagesClass" ng-messages-multiple> <div ng-message="pattern" class="ngMessageClass">* This field is invalid, only numbers are allowed</div> <div ng-message="minlength" class="ngMessageClass">* It's mandatory at least 5 characters</div> <div ng-message="maxlength" class="ngMessageClass">* It's mandatory at most 10 characters</div> </div> </div> </form> </div> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular-animate.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular-messages.min.js"></script> <script> var app = angular.module('myApp', ['ngAnimate', 'ngMessages']); </script> </body> </html> We included the ngMessage file too, as it's required for this sample. For the ngMessages directive, that is, the container of the ngMessage directives, we included an animation on ng-active-addthat changes the container background color from white to red and ng-inactive-add that does the opposite, changing the background color from red to white. This works because the ngMessages directive appends the ng-active class when there is any message to be displayed. When there is no message, it appends the ng-inactive class to the element. Let's see the ngMessages animation's declaration: .ngMessagesClass { height: 50px; width: 350px; } .ngMessagesClass.ng-active-add { transition: 0.3s linear all; background-color: red; } .ngMessagesClass.ng-active { background-color: red; } .ngMessagesClass.ng-inactive-add { transition: 0.3s linear all; background-color: white; } .ngMessagesClass.ng-inactive { background-color: white; } For the ngMessage directive, which contains a message, we created an animation that changes the color of the error message from transparent to white when the message enters the DOM, and changes the color from white to transparent when the message leaves DOM, shown as follows: .ngMessageClass { color: white; } .ngMessageClass.ng-enter { transition: 0.3s linear all; color: transparent; } .ngMessageClass.ng-enter-active { color: white; } .ngMessageClass.ng-leave { transition: 0.3s linear all; color: white; } .ngMessageClass.ng-leave-active { color: transparent; } This sample illustrates two animations for two directives that are related to each other. The initial result, before we add a password, is as follows: We can see both animations being triggered when we type in the a character, for example, in the password input. Between 0 and 300 ms of the animation, we will see both the background and text appearing for two validation messages: After 300 ms, the animation has completed, and the output is as follows: The ngView directive animation The ngView directive is used to add a template to the main layout. It has support for animation, for both enter and leave events. It's nice to have an animation for ngView, so the user has a better notion that we are switching views. For this directive sample, we need to add the ngRoute JavaScript file to the HTML and the ngRoute module as a dependency of our app. We will create a sample that slides the content of the current view to the left, and the new view appears sliding from the right to the left too so that we can see the current view leaving and the next view appearing. Consider the following HTML: <!DOCTYPE html> <html ng-app="myApp"> <head> <title>AngularJS ngView sample</title> </head> <body> <style> .ngViewRelative { position: relative; height: 300px; } .ngViewContainer { position: absolute; width: 500px; display: block; } .ngViewContainer.ng-enter, .ngViewContainer.ng-leave { -webkit-transition: 600ms linear all; transition: 600ms linear all; } .ngViewContainer.ng-enter { transform: translateX(500px); } .ngViewContainer.ng-enter-active { transform: translateX(0px); } .ngViewContainer.ng-leave { transform: translateX(0px); } .ngViewContainer.ng-leave-active { transform: translateX(-1000px); } </style> <h1>ngView sample</h1> <div class="ngViewRelative"> <a href="#/First">First page</a> <a href="#/Second">Second page</a> <div ng-view class="ngViewContainer"> </div> </div> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular-animate.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular-route.min.js"></script> <script> var app = angular.module('myApp', ['ngAnimate', 'ngRoute']); app.config(['$routeProvider', function ($routeProvider) { $routeProvider .when('/First', { templateUrl: 'first.html' }) .when('/Second', { templateUrl: 'second.html' }) .otherwise({ redirectTo: '/First' }); }]); </script> </body> </html> We need to configure the routes on config, as the JavaScript shows us. We then create the two HTML templates on the same directory. The content of the templates are just plain lorem ipsum. The first.html file content is shown as follows: <div> <h2>First page</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras consectetur dui nunc, vel feugiat lectus imperdiet et. In hac habitasse platea dictumst. In rutrum malesuada justo, sed porttitor dolor rutrum eu. Sed condimentum tempus est at euismod. Donec in faucibus urna. Fusce fermentum in mauris at pretium. Aenean ut orci nunc. Nulla id velit interdum nibh feugiat ultricies eu fermentum dolor. Pellentesque lobortis rhoncus nisi, imperdiet viverra leo ullamcorper sed. Donec condimentum tincidunt mollis. Curabitur lorem nibh, mattis non euismod quis, pharetra eu nibh. </p> </div> The second.html file content is shown as follows: <div> <h2>Second page</h2> <p> Ut eu metus vel ipsum tristique fringilla. Proin hendrerit augue quis nisl pellentesque posuere. Aliquam sollicitudin ligula elit, sit amet placerat augue pulvinar eget. Aliquam bibendum pulvinar nisi, quis commodo lorem volutpat in. Donec et felis sit amet mauris venenatis feugiat non id metus. Fusce leo elit, egestas non turpis sed, tincidunt consequat tellus. Fusce quis auctor neque, a ultricies urna. Cras varius purus id sagittis luctus. Sed id lectus tristique, euismod ipsum ut, congue augue. </p> </div> Great, we now have our app set up to enable ngView and routes. The animation was defined by adding animation to the enter and leave events, using translateX(). This animation is defined to the new view coming from 500 px from the right and animating until the position on the x-axis is 0, leaving the view in the left corner. The leaving view goes from the initial position until it is at -1000 px on the x-axis. Then, it leaves the DOM. This animation creates a sliding effect; the leaving view leaves faster as it has to move the double of the distance of the entering view in the same animation duration. We can change the translation using the y-axis to change the animation direction, creating the same sliding effect but with different aesthetics. The ngSwitch directive animation The ngSwitch directive is a directive that is used to conditionally swap the DOM structure based on an expression. It supports animation on the enter and leave events, for example, the ngView directive animation events. For this sample, we will create the same sliding effect of the ngView sample, but in this case, we will create a sliding effect from top to bottom instead of right to left. This animation helps the user to understand that one item is being replaced by the other. The ngSwitch sample HTML is shown as follows: <!DOCTYPE html> <html ng-app="myApp"> <head> <title>AngularJS ngSwitch sample</title> </head> <body> <div ng-controller="animationsCtrl"> <h1>ngSwitch sample</h1> <p>Choose an item:</p> <select ng-model="ngSwitchSelected" ng-options="item for item in ngSwitchItems"></select> <p>Selected item:</p> <div class="switchItemRelative" ng-switch on="ngSwitchSelected"> <div class="switchItem" ng-switch-when="item1">Item 1</div> <div class="switchItem" ng-switch-when="item2">Item 2</div> <div class="switchItem" ng-switch-when="item3">Item 3</div> <div class="switchItem" ng-switch-default>Default Item</div> </div> </div> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular-animate.min.js"></script> <script> var app = angular.module('myApp', ['ngAnimate']); app.controller('animationsCtrl', function ($scope) { $scope.ngSwitchItems = ['item1', 'item2', 'item3']; }); </script> </body> </html> In the JavaScript controller, we added the ngSwitchItems array to the scope, and the animation CSS is defined as follows: /* ngSwitch animation */ .switchItemRelative { position: relative; height: 25px; overflow: hidden; } .switchItem { position: absolute; width: 500px; display: block; } /*The transition is added when the switch item is about to enter or about to leave DOM*/ .switchItem.ng-enter, .switchItem.ng-leave { -webkit-transition: 300ms linear all; -moz-transition: 300ms linear all; -ms-transition: 300ms linear all; -o-transition: 300ms linear all; transition: 300ms linear all; } /* When the element is about to enter DOM*/ .switchItem.ng-enter { bottom: 100%; } /* When the element completes the enter transition */ .switchItem.ng-enter-active { bottom: 0; } /* When the element is about to leave DOM*/ .switchItem.ng-leave { bottom: 0; } /*When the element end the leave transition*/ .switchItem.ng-leave-active { bottom: -100%; } This is almost the same CSS as the ngView sample; we just used the bottom property, added a different height to the switchItemRelative class, and included overflow:hidden. The ngInclude directive sample The ngInclude directive is used to fetch, compile, and include an HTML fragment; it supports animations for the enter and leave events, such as the ngView and ngSwitch directives. For this sample, we will use both templates created in the last ngView sample, first.html and second.html. The ngInclude animation sample HTML with JavaScript and CSS included is shown as follows: <!DOCTYPE html> <html ng-app="myApp"> <head> <title>AngularJS ngInclude sample</title> </head> <body> <style> .ngIncludeRelative { position: relative; height: 500px; overflow: hidden; } .ngIncludeItem { position: absolute; width: 500px; display: block; } .ngIncludeItem.ng-enter, .ngIncludeItem.ng-leave { -webkit-transition: 300ms linear all; transition: 300ms linear all; } .ngIncludeItem.ng-enter { top: 100%; } .ngIncludeItem.ng-enter-active { top: 0; } .ngIncludeItem.ng-leave { top: 0; } .ngIncludeItem.ng-leave-active { top: -100%; } </style> <div ng-controller="animationsCtrl"> <h1>ngInclude sample</h1> <p>Choose one template</p> <select ng-model="ngIncludeSelected" ng-options="item.name for item in ngIncludeTemplates"></select> <p>ngInclude:</p> <div class="ngIncludeRelative"> <div class="ngIncludeItem" nginclude=" ngIncludeSelected.url"></div> </div> </div> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs /1.3.0/angular-animate.min.js"></script> <script> var app = angular.module('myApp', ['ngAnimate']); app.controller('animationsCtrl', function ($scope) { $scope.ngIncludeTemplates = [{ name: 'first', url: 'first.html' }, { name: 'second', url: 'second.html' }]; }) </script> </body> </html> In the JavaScript controller, we included the templates array. Finally, we can animate ngInclude using CSS. In this sample, we will animate by sliding the templates using the top property, using the enter and leave events animation. To test this sample, just change the template value selected. Do it yourself exercises The following are some exercises that you can refer to as an exercise that will help you understand the concepts of this article better: Create a spinning loading animation, using the ngShow or ngHide directives that appears when the scope controller variable, $scope.isLoading, is equal to true. Using exercise 1, create a gray background layer with opacity 0.5 that smoothly fills the entire page behind the loading spin, and after page content is loaded, covers all the content until isProcessing becomes false. The effect should be that of a drop of ink that is dropped on a piece of paper and spreads until it's completely stained. Create a success notification animation, similar to the ngShow example, but instead of using the fade animation, use a slide-down animation. So, the success message starts with height:0px. Check http://api.jquery.com/slidedown/ for the expected animation effect. Copy any animation from the http://capptivate.co/ website, using AngularJS and CSS animations. Summary In this article, we learned how to animate AngularJS native directives using the CSS transitions and CSS keyframe concepts. This article taught you how to create animations on AngularJS web apps. Resources for Article: Further resources on this subject: Important Aspect of AngularJS UI Development [article] Setting Up The Rig [article] AngularJS Project [article]
Read more
  • 0
  • 0
  • 3109

article-image-loading-data-creating-app-and-adding-dashboards-and-reports-splunk
Packt
31 Oct 2014
13 min read
Save for later

Loading data, creating an app, and adding dashboards and reports in Splunk

Packt
31 Oct 2014
13 min read
In this article by Josh Diakun, Paul R Johnson, and Derek Mock, authors of Splunk Operational Intelligence Cookbook, we will take a look at how to load sample data into Splunk, how to create an application, and how to add dashboards and reports in Splunk. (For more resources related to this topic, see here.) Loading the sample data While most of the data you will index with Splunk will be collected in real time, there might be instances where you have a set of data that you would like to put into Splunk, either to backfill some missing or incomplete data, or just to take advantage of its searching and reporting tools. This recipe will show you how to perform one-time bulk loads of data from files located on the Splunk server. We will also use this recipe to load the data samples that will be used as we build our Operational Intelligence app in Splunk. There are two files that make up our sample data. The first is access_log, which represents data from our web layer and is modeled on an Apache web server. The second file is app_log, which represents data from our application layer and is modeled on the log4j application log data. Getting ready To step through this recipe, you will need a running Splunk server and should have a copy of the sample data generation app (OpsDataGen.spl). (This file is part of the downloadable code bundle, which is available on the book's website.) How to do it... Follow the given steps to load the sample data generator on your system: Log in to your Splunk server using your credentials. From the home launcher, select the Apps menu in the top-left corner and click on Manage Apps. Select Install App from file. Select the location of the OpsDataGen.spl file on your computer, and then click on the Upload button to install the application. After installation, a message should appear in a blue bar at the top of the screen, letting you know that the app has installed successfully. You should also now see the OpsDataGen app in the list of apps. By default, the app installs with the data-generation scripts disabled. In order to generate data, you will need to enable either a Windows or Linux script, depending on your Splunk operating system. To enable the script, select the Settings menu from the top-right corner of the screen, and then select Data inputs. From the Data inputs screen that follows, select Scripts. On the Scripts screen, locate the OpsDataGen script for your operating system and click on Enable. For Linux, it will be $SPLUNK_HOME/etc/apps/OpsDataGen/bin/AppGen.path For Windows, it will be $SPLUNK_HOMEetcappsOpsDataGenbinAppGen-win.path The following screenshot displays both the Windows and Linux inputs that are available after installing the OpsDataGen app. It also displays where to click to enable the correct one based on the operating system Splunk is installed on. Select the Settings menu from the top-right corner of the screen, select Data inputs, and then select Files & directories. On the Files & directories screen, locate the two OpsDataGen inputs for your operating system and for each click on Enable. For Linux, it will be: $SPLUNK_HOME/etc/apps/OpsDataGen/data/access_log $SPLUNK_HOME/etc/apps/OpsDataGen/data/app_log For Windows, it will be: $SPLUNK_HOMEetcappsOpsDataGendataaccess_log $SPLUNK_HOMEetcappsOpsDataGendataapp_log The following screenshot displays both the Windows and Linux inputs that are available after installing the OpsDataGen app. It also displays where to click to enable the correct one based on the operating system Splunk is installed on. The data will now be generated in real time. You can test this by navigating to the Splunk search screen and running the following search over an All time (real-time) time range: index=main sourcetype=log4j OR sourcetype=access_combined After a short while, you should see data from both source types flowing into Splunk, and the data generation is now working as displayed in the following screenshot: How it works... In this case, you installed a Splunk application that leverages a scripted input. The script we wrote generates data for two source types. The access_combined source type contains sample web access logs, and the log4j source type contains application logs. Creating an Operational Intelligence application This recipe will show you how to create an empty Splunk app that we will use as the starting point in building our Operational Intelligence application. Getting ready To step through this recipe, you will need a running Splunk Enterprise server, with the sample data loaded from the previous recipe. You should be familiar with navigating the Splunk user interface. How to do it... Follow the given steps to create the Operational Intelligence application: Log in to your Splunk server. From the top menu, select Apps and then select Manage Apps. Click on the Create app button. Complete the fields in the box that follows. Name the app Operational Intelligence and give it a folder name of operational_intelligence. Add in a version number and provide an author name. Ensure that Visible is set to Yes, and the barebones template is selected. When the form is completed, click on Save. This should be followed by a blue bar with the message, Successfully saved operational_intelligence. Congratulations, you just created a Splunk application! How it works... When an app is created through the Splunk GUI, as in this recipe, Splunk essentially creates a new folder (or directory) named operational_intelligence within the $SPLUNK_HOME/etc/apps directory. Within the $SPLUNK_HOME/etc/apps/operational_intelligence directory, you will find four new subdirectories that contain all the configuration files needed for our barebones Operational Intelligence app that we just created. The eagle-eyed among you would have noticed that there were two templates, barebones and sample_app, out of which any one could have been selected when creating the app. The barebones template creates an application with nothing much inside of it, and the sample_app template creates an application populated with sample dashboards, searches, views, menus, and reports. If you wish to, you can also develop your own custom template if you create lots of apps, which might enforce certain color schemes for example. There's more... As Splunk apps are just a collection of directories and files, there are other methods to add apps to your Splunk Enterprise deployment. Creating an application from another application It is relatively simple to create a new app from an existing app without going through the Splunk GUI, should you wish to do so. This approach can be very useful when we are creating multiple apps with different inputs.conf files for deployment to Splunk Universal Forwarders. Taking the app we just created as an example, copy the entire directory structure of the operational_intelligence app and name it copied_app. cp -r $SPLUNK_HOME$/etc/apps/operational_intelligence/* $SPLUNK_HOME$/etc/apps/copied_app Within the directory structure of copied_app, we must now edit the app.conf file in the default directory. Open $SPLUNK_HOME$/etc/apps/copied_app/default/app.conf and change the label field to My Copied App, provide a new description, and then save the conf file. ## Splunk app configuration file#[install]is_configured = 0[ui]is_visible = 1label = My Copied App[launcher]author = John Smithdescription = My Copied applicationversion = 1.0 Now, restart Splunk, and the new My Copied App application should now be seen in the application menu. $SPLUNK_HOME$/bin/splunk restart Downloading and installing a Splunk app Splunk has an entire application website with hundreds of applications, created by Splunk, other vendors, and even users of Splunk. These are great ways to get started with a base application, which you can then modify to meet your needs. If the Splunk server that you are logged in to has access to the Internet, you can click on the Apps menu as you did earlier and then select the Find More Apps button. From here, you can search for apps and install them directly. An alternative way to install a Splunk app is to visit http://apps.splunk.com and search for the app. You will then need to download the application locally. From your Splunk server, click on the Apps menu and then on the Manage Apps button. After that, click on the Install App from File button and upload the app you just downloaded, in order to install it. Once the app has been installed, go and look at the directory structure that the installed application just created. Familiarize yourself with some of the key files and where they are located. When downloading applications from the Splunk apps site, it is best practice to test and verify them in a nonproduction environment first. The Splunk apps site is community driven and, as a result, quality checks and/or technical support for some of the apps might be limited. Adding dashboards and reports Dashboards are a great way to present many different pieces of information. Rather than having lots of disparate dashboards across your Splunk environment, it makes a lot of sense to group related dashboards into a common Splunk application, for example, putting operational intelligence dashboards into a common Operational Intelligence application. In this recipe, you will learn how to move the dashboards and associated reports into our new Operational Intelligence application. Getting ready To step through this recipe, you will need a running Splunk Enterprise server, with the sample data loaded from the Loading the sample data recipe. You should be familiar with navigating the Splunk user interface. How to do it... Follow these steps to move your dashboards into the new application: Log in to your Splunk server. Select the newly created Operational Intelligence application. From the top menu, select Settings and then select the User interface menu item. Click on the Views section. In the App Context dropdown, select Searching & Reporting (search) or whatever application you were in when creating the dashboards: Locate the website_monitoring dashboard row in the list of views and click on the Move link to the right of the row. In the Move Object pop up, select the Operational Intelligence (operational_intelligence) application that was created earlier and then click on the Move button. A message bar will then be displayed at the top of the screen to confirm that the dashboard was moved successfully. Repeat from step 5 to move the product_monitoring dashboard as well. After the Website Monitoring and Product Monitoring dashboards have been moved, we now want to move all the reports that were created, as these power the dashboards and provide operational intelligence insight. From the top menu, select Settings and this time select Searches, reports, and alerts. Select the Search & Reporting (search) context and filter by cp0* to view the searches (reports) that are created. Click on the Move link of the first cp0* search in the list. Select to move the object to the Operational Intelligence (operational_intelligence) application and click on the Move button. A message bar will then be displayed at the top of the screen to confirm that the dashboard was moved successfully. Select the Search & Reporting (search) context and repeat from step 11 to move all the other searches over to the new Operational Intelligence application—this seems like a lot but will not take you long! All of the dashboards and reports are now moved over to your new Operational Intelligence application. How it works... In the previous recipe, we revealed how Splunk apps are essentially just collections of directories and files. Dashboards are XML files found within the $SPLUNK_HOME/etc/apps directory structure. When moving a dashboard from one app to another, Splunk is essentially just moving the underlying file from a directory inside one app to a directory in the other app. In this recipe, you moved the dashboards from the Search & Reporting app to the Operational Intelligence app, as represented in the following screenshot: As visualizations on the dashboards leverage the underlying saved searches (or reports), you also moved these reports to the new app so that the dashboards maintain permissions to access them. Rather than moving the saved searches, you could have changed the permissions of each search to Global such that they could be seen from all the other apps in Splunk. However, the other reason you moved the reports was to keep everything contained within a single Operational Intelligence application, which you will continue to build on going forward. It is best practice to avoid setting permissions to Global for reports and dashboards, as this makes them available to all the other applications when they most likely do not need to be. Additionally, setting global permissions can make things a little messy from a housekeeping perspective and crowd the lists of reports and views that belong to specific applications. The exception to this rule might be for knowledge objects such as tags, event types, macros, and lookups, which often have advantages to being available across all applications. There's more… As you went through this recipe, you likely noticed that the dashboards had application-level permissions, but the reports had private-level permissions. The reports are private as this is the default setting in Splunk when they are created. This private-level permission restricts access to only your user account and admin users. In order to make the reports available to other users of your application, you will need to change the permissions of the reports to Shared in App as we did when adjusting the permissions of reports. Changing the permissions of saved reports Changing the sharing permission levels of your reports from the default Private to App is relatively straightforward: Ensure that you are in your newly created Operational Intelligence application. Select the Reports menu item to see the list of reports. Click on Edit next to the report you wish to change the permissions for. Then, click on Edit Permissions from the drop-down list. An Edit Permissions pop-up box will appear. In the Display for section, change from Owner to App, and then, click on Save. The box will close, and you will see that the Sharing permissions in the table will now display App for the specific report. This report will now be available to all the users of your application. Summary In this article, we loaded the sample data into Splunk. We also saw how to organize dashboards and knowledge into a custom Splunk app. Resources for Article: Further resources on this subject: VWorking with Pentaho Mobile BI [Article] Visualization of Big Data [Article] Highlights of Greenplum [Article]
Read more
  • 0
  • 0
  • 10125
article-image-distributed-rails-applications-with-chef
Rahmal Conda
31 Oct 2014
4 min read
Save for later

Configuring Distributed Rails Applications with Chef: Part 1

Rahmal Conda
31 Oct 2014
4 min read
Since the Advent of Rails (and Ruby by extension), in the period between 2005 and 2010, Rails went from a niche Web Application Framework to being the center of a robust web application platform. To do this it needed more than Ruby and a few complementary gems. Anyone who has ever tried to deploy a Rails application into a production environment knows that Rails doesn’t run in a vacuum. Rails still needs a web server in front of it to help manage requests like Apache or Nginx. Oops, you’ll need unicorn or Passenger too. Almost all of the Rails apps are backed by some sort of data persistence layer. Usually that is some sort of relational database. More and more it’s a NoSQL DB like MongoDB or depending on the application, you’re probably going to deploy a caching strategy at some point: Memcached, Redis, the list goes on. What about background jobs? You’ll need another server instance for that too, and not just one either. High availability systems need to be redundant. If you’re lucky enough to get a lot of traffic, you’ll need a way to scale all of this. Why Chef? Chances are that you’re managing all of this traffic manually. Don’t feel bad, everyone starts out that way. But as you grow, how do you manage all of this without going insane? Most Rails developers start off with Capistrano, which is a great choice. Capistrano is a remote server automation tool. It’s used most often as a deployment tool for Rails. For the most part it’s a great solution for managing multiple servers that make up your Rails stack. It’s only when your architecture reaches a certain size that I’d recommend choosing Chef over Capistrano. But really, there’s no reason to choose one over the other since they actually work pretty well together, and they are both similar regarding deployment. Where Chef excels, however, is when you need to provision multiple servers with different roles, and changing software stacks. This is what I’m going to focus on in this post. But let’s introduce Chef first. What is Chef anyway? Basically, Chef is a Ruby-based configuration management engine. It is a software configuration management tool, used for provisioning servers for certain roles within a platform stack, and deploying applications to those servers. It is used to automate server configuration and integration into your infrastructure. You define your infrastructure in configuration files written in Chef’s Ruby DSL and Chef takes care of setting up individual machines and linking them together. Chef server You set up one of your server instances (virtual or otherwise) as the server and all your other instances are clients that communicate with the Chef "server" via REST over HTTPS. The server is an application that stores cookbooks for your nodes. Recipes and cookbooks Recipes are files that contain sets of instructions written in Chef’s Ruby DSL. These instructions perform some kind of procedure, usually installing software and configuring some service. These recipes are bound together along with configuration file templates, resources, and helper scripts as cookbooks. Cookbooks generally correspond to a specific server configuration. For instance, a Postgres cookbook might contain a recipe for Postgres Server, Postgres Client, maybe PostGIS, and some configuration files for how the DB instance should be provisioned. Chef Solo For stacks that don’t necessarily need a full Chef server setup, but use cookbooks to set up Rails and DB servers, there’s Chef Solo. Chef Solo is a local standalone Chef application that can be used to remotely deploy servers and applications. Wait, where is the code? In Part 2 of this post I’m going to walk you through the setting up of a Rails application with Chef Solo, then I’ll expand to show a full Chef server configuration management engine. While Chef can be used for many different application stacks, I’m going to focus on Rails configuration and deployment, provisioning and deploying the entire stack. See you next time! About the Author Rahmal Conda is a Software Development Professional and Ruby aficionado from Chicago. After 10 years working in web and application development, he moved out to the Bay Area, eager to join the startup scene. He had a taste of the startup life in Chicago working at a small personal finance company. After that he knew it was the life he had been looking for. So he moved his family out west. Since then he's made a name for himself in the social space at some high profile Silicon Valley startups. Right now he's the one of the Co-founders and Platform Architect of Boxes, a mobile marketplace for the world's hidden treasures.
Read more
  • 0
  • 0
  • 4141

article-image-untangle-vpn-services
Packt
30 Oct 2014
18 min read
Save for later

Untangle VPN Services

Packt
30 Oct 2014
18 min read
This article by Abd El-Monem A. El-Bawab, the author of Untangle Network Security, covers the Untangle solution, OpenVPN. OpenVPN is an SSL/TLS-based VPN, which is mainly used for remote access as it is easy to configure and uses clients that can work on multiple operating systems and devices. OpenVPN can also provide site-to-site connections (only between two Untangle servers) with limited features. (For more resources related to this topic, see here.) OpenVPN Untangle's OpenVPN is an SSL-based VPN solution that is based on the well-known open source application, OpenVPN. Untangle's OpenVPN is mainly used for client-to-site connections with a client feature that is easy to deploy and configure, which is widely available for Windows, Mac, Linux, and smartphones. Untangle's OpenVPN can also be used for site-to-site connections but the two sites need to have Untangle servers. Site-to-site connections between Untangle and third-party devices are not supported. How OpenVPN works In reference to the OSI model, an SSL/TLS-based VPN will only encrypt the application layer's data, while the lower layer's information will be transferred unencrypted. In other words, the application packets will be encrypted. The IP addresses of the server and client are visible; the port number that the server uses for communication between the client and server is also visible, but the actual application port number is not visible. Furthermore, the destination IP address will not be visible; only the VPN server IP address is seen. Secure Sockets Layer (SSL) and Transport Layer Security (TLS) refer to the same thing. SSL is the predecessor of TLS. SSL was originally developed by Netscape and many releases were produced (V.1 to V.3) till it got standardized under the TLS name. The steps to create an SSL-based VPN are as follows: The client will send a message to the VPN server that it wants to initiate an SSL session. Also, it will send a list of all ciphers (hash and encryption protocols) that it supports. The server will respond with a set of selected ciphers and will send its digital certificate to the client. The server's digital certificate includes the server's public key. The client will try to verify the server's digital certificate by checking it against trusted certificate authorities and by checking the certificate's validity (valid from and valid through dates). The server may need to authenticate the client before allowing it to connect to the internal network. This could be achieved either by asking for a valid username and password or by using the user's digital identity certificates. Untangle NGFW uses the digital certificates method. The client will create a session key (which will be used to encrypt the transferred data between the two devices) and will send this key to the server encrypted using the server's public key. Thus, no third party can get the session key as the server is the only device that can decrypt the session key as it's the only party that has the private key. The server will acknowledge the client that it received the session key and is ready for the encrypted data transformation. Configuring Untangle's OpenVPN server settings After installing the OpenVPN application, the application will be turned off. You'll need to turn it on before you can use it. You can configure Untangle's OpenVPN server settings under OpenVPN settings | Server. The settings configure how OpenVPN will be a server for remote clients (which can be clients on Windows, Linux, or any other operating systems, or another Untangle server). The different available settings are as follows: Site Name: This is the name of the OpenVPN site that is used to define the server among other OpenVPN servers inside your origination. This name should be unique across all Untangle servers in the organization. A random name is automatically chosen for the site name. Site URL: This is the URL that the remote client will use to reach this OpenVPN server. This can be configured under Config | Administration | Public Address. If you have more than one WAN interface, the remote client will first try to initiate the connection using the settings defined in the public address. If this fails, it will randomly try the IP of the remaining WAN interfaces. Server Enabled: If checked, the OpenVPN server will run and accept connections from the remote clients. Address Space: This defines the IP subnet that will be used to assign IPs for the remote VPN clients. The value in Address Space must be unique and separate across all existing networks and other OpenVPN address spaces. A default address space will be chosen that does not conflict with the existing configuration: Configuring Untangle's OpenVPN remote client settings Untangle's OpenVPN allows you to create OpenVPN clients to give your office employees, who are out of the company, the ability to remotely access your internal network resources via their PCs and/or smartphones. Also, an OpenVPN client can be imported to another Untangle server to provide site-to-site connection. Each OpenVPN client will have its unique IP (from the address space range defined previously). Thus, each OpenVPN client can only be used for one user. For multiple users, you'll have to create multiple clients as using the same client for multiple users will result in client disconnection issues. Creating a remote client You can create remote access clients by clicking on the Add button located under OpenVPN Settings | Server | Remote Clients. A new window will open, which has the following settings: Enabled: If this checkbox is checked, it will allow the client connection to the OpenVPN server. If unchecked, it will not allow the client connection. Client Name: Give a unique name for the client; this will help you identify the client. Only alphanumeric characters are allowed. Group: Specify the group the client will be a member of. Groups are used to apply similar settings to their members. Type: Select Individual Client for remote access and Network for site-to-site VPN. The following screenshot shows a remote access client created for JDoe: After configuring the client settings, you'll need to press the Done button and then the OK or Apply button to save this client configuration. The new client will be available under the Remote Clients tab, as shown in the following screenshot: Understanding remote client groups Groups are used to group clients together and apply similar settings to the group members. By default, there will be a Default Group. Each group has the following settings: Group Name: Give a suitable name for the group that describes the group settings (for example, full tunneling clients) or the target clients (for example, remote access clients). Full Tunnel: If checked, all the traffic from the remote clients will be sent to the OpenVPN server, which allows Untangle to filter traffic directed to the Internet. If unchecked, the remote client will run in the split tunnel mode, which means that the traffic directed to local resources behind Untangle is sent through VPN, and the traffic directed to the Internet is sent by the machine's default gateway. You can't use Full Tunnel for site-to-site connections. Push DNS: If checked, the remote OpenVPN client will use the DNS settings defined by the OpenVPN server. This is useful to resolve local names and services. Push DNS server: If the OpenVPN server is selected, remote clients will use the OpenVPN server for DNS queries. If set to Custom, DNS servers configured here will be used for DNS queries. Push DNS Custom 1: If the Push DNS server is set to Custom, the value configured here will be used as a primary DNS server for the remote client. If blank, no settings will be pushed for the remote client. Push DNS Custom 2: If the Push DNS server is set to Custom, the value configured here will be used as a secondary DNS server for the remote client. If blank, no settings will be pushed for the remote client. Push DNS Domain: The configured value will be pushed to the remote clients to extend their domain's search path during DNS resolution. The following screenshot illustrates all these settings: Defining the exported networks Exported networks are used to define the internal networks behind the OpenVPN server that the remote client can reach after successful connection. Additional routes will be added to the remote client's routing table that state that the exported networks (the main site's internal subnet) are reachable through the OpenVPN server. By default, each static non-WAN interface network will be listed in the Exported Networks list: You can modify the default settings or create new entries. The Exported Networks settings are as follows: Enabled: If checked, the defined network will be exported to the remote clients. Export Name: Enter a suitable name for the exported network. Network: This defines the exported network. The exported network should be written in CIDR form. These settings are illustrated in the following screenshot: Using OpenVPN remote access clients So far, we have been configuring the client settings but didn't create the real package to be used on remote systems. We can get the remote client package by pressing the Download Client button located under OpenVPN Settings | Server | Remote Clients, which will start the process of building the OpenVPN client that will be distributed: There are three available options to download the OpenVPN client. The first option is to download the client as a .exe file to be used with the Windows operating system. The second option is to download the client configuration files, which can be used with the Apple and Linux operating systems. The third option is similar to the second one except that the configuration file will be imported to another Untangle NGFW server, which is used for site-to-site scenarios. The following screenshot illustrates this: The configuration files include the following files: <Site_name>.ovpn <Site_name>.conf Keys<Site_name>.-<User_name>.crt Keys<Site_name>.-<User_name>.key Keys<Site_name>.-<User_name>-ca.crt The certificate files are for the client authentication, and the .ovpn and .conf files have the defined connection settings (that is, the OpenVPN server IP, used port, and used ciphers). The following screenshot shows the .ovpn file for the site Untangle-1849: As shown in the following screenshot, the created file (openvpn-JDoe-setup.exe) includes the client name, which helps you identify the different clients and simplifies the process of distributing each file to the right user: Using an OpenVPN client with Windows OS Using an OpenVPN client with the Windows operating system is really very simple. To do this, perform the following steps: Set up the OpenVPN client on the remote machine. The setup is very easy and it's just a next, next, install, and finish setup. To set up and run the application as an administrator is important in order to allow the client to write the VPN routes to the Windows routing table. You should run the client as an administrator every time you use it so that the client can create the required routes. Double-click on the OpenVPN icon on the Windows desktop: The application will run in the system tray: Right-click on the system tray of the application and select Connect. The client will start to initiate the connection to the OpenVPN server and a window with the connection status will appear, as shown in the following screenshot: Once the VPN tunnel is initiated, a notification will appear from the client with the IP assigned to it, as shown in the following screenshot: If the OpenVPN client was running in the task bar and there was an established connection, the client will automatically reconnect to the OpenVPN server if the tunnel was dropped due to Windows being asleep. By default, the OpenVPN client will not start at the Windows login. We can change this and allow it to start without requiring administrative privileges by going to Control Panel | Administrative Tools | Services and changing the OpenVPN service's Startup Type to automatic. Now, in the start parameters field, put –-connect <Site_name>.ovpn; you can find the <site_name>.ovpn under C:Program FilesOpenVPNconfig. Using OpenVPN with non-Windows clients The method to configure OpenVPN clients to work with Untangle is the same for all non-Windows clients. Simply download the .zip file provided by Untangle, which includes the configuration and certificate files, and place them into the application's configuration folder. The steps are as follows: Download and install any of the following OpenVPN-compatible clients for your operating system: For Mac OS X, Untangle, Inc. suggests using Tunnelblick, which is available at http://code.google.com/p/tunnelblick For Linux, OpenVPN clients for different Linux distros can be found at https://openvpn.net/index.php/access-server/download-openvpn-as-sw.html OpenVPN connect for iOS is available at https://itunes.apple.com/us/app/openvpn-connect/id590379981?mt=8 OpenVPN for Android 4.0+ is available at https://play.google.com/store/apps/details?id=net.openvpn.openvpn Log in to the Untangle NGFW server, download the .zip client configuration file, and extract the files from the .zip file. Place the configuration files into any of the following OpenVPN-compatible applications: Tunnelblick: Manually copy the files into the Configurations folder located at ~/Library/Application Support/Tunnelblick. Linux: Copy the extracted files into /etc/openvpn, and then you can connect using sudo openvpn /etc/openvpn/<Site_name>.conf. iOS: Open iTunes and select the files from the config ZIP file to add to the app on your iPhone or iPad. Android: From OpenVPN for an Android application, click on all your precious VPNs. In the top-right corner, click on the folder, and then browse to the folder where you have the OpenVPN .Conf file. Click on the file and hit Select. Then, in the top-right corner, hit the little floppy disc icon to save the import. Now, you should see the imported profile. Click on it to connect to the tunnel. For more information on this, visit http://forums.untangle.com/openvpn/30472-openvpn-android-4-0-a.html. Run the OpenVPN-compatible client. Using OpenVPN for site-to-site connection To use OpenVPN for site-to-site connection, one Untangle NGFW server will run on the OpenVPN server mode, and the other server will run on the client mode. We will need to create a client that will be imported in the remote server. The client settings are shown in the following screenshot: We will need to download the client configuration that is supposed to be imported on another Untangle server (the third option available on the client download menu), and then import this client configuration's zipped file on the remote server. To import the client, on the remote server under the Client tab, browse to the .zip file and press the Submit button. The client will be shown as follows: You'll need to restart the two servers before being able to use the OpenVPN site-to-site connection. The site-to-site connection is bidirectional. Reviewing the connection details The current connected clients (either they were OS clients or another Untangle NGFW client) will appear under Connected Remote Clients located under the Status tab. The screen will show the client name, its external address, and the address assigned to it by OpenVPN. In addition to the connection start time, the amount of transmitted and received MB during this connection is also shown: For the site-to-site connection, the client server will show the name of the remote server, whether the connection is established or not, in addition to the amount of transmitted and received data in MB: Event logs show a detailed connection history as shown in the following screenshot: In addition, there are two reports available for Untangle's OpenVPN: Bandwidth usage: This report shows the maximum and average data transfer rate (KB/s) and the total amount of data transferred that day Top users: This report shows the top users connected to the Untangle OpenVPN server Troubleshooting Untangle's OpenVPN In this section, we will discuss some points to consider when dealing with Untangle NGFW OpenVPN. OpenVPN acts as a router as it will route between different networks. Using OpenVPN with Untangle NGFW in the bridge mode (Untangle NGFW server is behind another router) requires additional configurations. The required configurations are as follows: Create a static route on the router that will route any traffic from the VPN range (the VPN address pool) to the Untangle NGFW server. Create a Port Forward rule for the OpenVPN port 1194 (UDP) on the router to Untangle NGFW. Verify that your setting is correct by going to Config | Administration | Public Address as it is used by Untangle to configure OpenVPN clients, and ensure that the configured address is resolvable from outside the company. If the OpenVPN client is connected, but you can't access anything, perform the following steps: Verify that the hosts you are trying to reach are exported in Exported Networks. Try to ping Untangle NGFW LAN IP address (if exported). Try to bring up the Untangle NGFW GUI by entering the IP address in a browser. If the preceding tasks work, your tunnel is up and operational. If you can't reach any clients inside the network, check for the following conditions: The client machine's firewall is not preventing the connection from the OpenVPN client. The client machine uses Untangle as a gateway or has a static route to send the VPN address pool to Untangle NGFW. In addition, some port forwarding rules on Untangle NGFW are needed for OpenVPN to function properly. The required ports are 53, 445, 389, 88, 135, and 1025. If the site-to-site tunnel is set up correctly, but the two sites can't talk to each other, the reason may be as follows: If your sites have IPs from the same subnet (this probably happens when you use a service from the same ISP for both branches), OpenVPN may fail as it consider no routing is needed from IPs in the same subnet, you should ask your ISP to change the IPs. To get DNS resolution to work over the site-to-site tunnel, you'll need to go to Config | Network | Advanced | DNS Server | Local DNS Servers and add the IP of the DNS server on the far side of the tunnel. Enter the domain in the Domain List column and use the FQDN when accessing resources. You'll need to do this on both sides of the tunnel for it to work from either side. If you are using site-to-site VPN in addition to the client-to-site VPN. However, the OpenVPN client is able to connect to the main site only: You'll need to add VPN Address Pool to Exported Hosts and Networks Lab-based training This section will provide training for the OpenVPN site-to-site and client-to-site scenarios. In this lab, we will mainly use Untangle-01, Untangle-03, and a laptop (192.168.1.7). The ABC bank started a project with Acme schools. As a part of this project, the ABC bank team needs to periodically access files located on Acme-FS01. So, the two parties decided to opt for OpenVPN. However, Acme's network team doesn't want to leave access wide open for ABC bank members, so they set firewall rules to limit ABC bank's access to the file server only. In addition, the IT team director wants to have VPN access from home to the Acme network, which they decided to accomplish using OpenVPN. The following diagram shows the environment used in the site-to-site scenario: To create the site-to-site connection, we will need to do the following steps: Enable OpenVPN Server on Untangle-01. Create a network type client with a remote network of 172.16.1.0/24. Download the client and import it under the Client tab in Untangle-03. Restart the two servers. After the restart, you have a site-to-site VPN connection. However, the Acme network is wide open to the ABC bank, so we need to create a firewall-limiting rule. On Untangle-03, create a rule that will allow any traffic that comes from the OpenVPN interface, and its source is 172.16.136.10 (Untangle-01 Client IP) and is directed to 172.16.1.7 (Acme-FS01). The rule is shown in the following screenshot: Also, we will need a general block rule that comes after the preceding rule in the rule evaluation order. The environment used for the client-to-site connection is shown in the following diagram: To create a client-to-site VPN connection, we need to perform the following steps: Enable the OpenVPN server on Untangle-03. Create an individual client type client on Untangle-03. Distribute the client to the intended user (that is 192.168.1.7). Install OpenVPN on your laptop. Connect using the installed OpenVPN and try to ping Acme-DC01 using its name. The ping will fail because the client is not able to query the Acme DNS. So, in the Default Group settings, change Push DNS Domain to Acme.local. Changing the group settings will not affect the OpenVPN client till the client is restarted. Now, the ping process will be a success. Summary In this article, we covered the VPN services provided by Untangle NGFW. We went deeply into understanding how each solution works. This article also provided a guide on how to configure and deploy the services. Untangle provides a free solution that is based on the well-known open source OpenVPN, which provides an SSL-based VPN. Resources for Article: Further resources on this subject: Important Features of Gitolite [Article] Target Exploitation [Article] IPv6 on Packet Tracer [Article]
Read more
  • 0
  • 0
  • 18642

article-image-planning-compliance-program-microsoft-system-center-2012
Packt
30 Oct 2014
16 min read
Save for later

Planning a Compliance Program in Microsoft System Center 2012

Packt
30 Oct 2014
16 min read
This article created by Andreas Baumgarten, Ronnie Isherwood, and Susan Roesner the authors of the book Microsoft System Center 2012 Compliance Management Cookbook, mentions all System Center Product we work with in the book. It also talks about responsibilities/stakeholders, and the reports involved. (For more resources related to this topic, see here.) Understanding the responsibilities of the System Center 2012 tools This recipe shows how the System Center tools, in addition to Security Compliance Manager, work together and it also explains the focus of each tool. Getting ready In order to create a successful compliance program, you must have a clear understanding of your goals and regulatory and business requirements. This information is key in understanding which control objectives are required and which control activities fulfill your goals and requirements, that is, your control objectives. How to do it... Based on your company and regulatory requirements, you must create your control objectives. There are libraries, such as the Unified Compliance Framework (UCF), that provide control objectives and control activities based on regulatory requirements such as privacy laws and frameworks such as COBIT, COSO, and so on. These compliance libraries are great tools to help you with this first step, but always keep in mind that they are just tools. The following diagram provides a visual summary of the tasks required for the successful creation of a technical compliance program showing which System Center tool to use for the different tasks. The tasks are as follows: Define compliance requirements Perform authorized implementation Review adherence to compliance requirements Perform remediation The minimum steps that are required are as follows: Define and document your compliance program, including compliance policies, standards, corresponding control objectives, and control activities. The results of this step are control objectives and control activities. Based on the scenario of access compliance, you should create a password policy that states the password rules and the reasons for the policy. This must be distributed to your users. With your policy and, more importantly, regulatory and company requirements in mind, decide on your control activities. The results of step 1 are the input for this task—for manual controls, use System Center Service Manager for documentation. The results are control status information. Based on the password policy scenario, in case no System Center Configuration Manager exists, the correct implementation of password policy would have to be checked manually. The result of this check should be entered into System Center Service Manager. This could either be entered in Incident or Change Management. Creating either one provides a record of the manual control and has the benefit of being included in the System Center Service Manager reports. The results of step 1 are the input for this task—for automated control activities based on configuration settings do the following: Use Security Compliance Manager to create compliance baselines for control activities of configuration settings. The result is the compliance baseline. Create a baseline with your password policy. The input is the compliance baseline from the previous step. Use Compliance Settings within System Center Configuration Manager to run the compliance baseline. The results are compliance control status information.Use the compliance baseline from Security Compliance Manager to ensure adherence to it. After configuring the controls, those will be run automatically. In addition, auto-remediation of failed controls is possible. The results of step 1 are inputs for this task—for automated control activities based on breach status, use Audit Collection Services from System Center Operations Manager. The results are compliance breach information. Based on the password policy scenario, create a monitoring rule for unauthorized access to critical systems and unauthorized changes to your password policy. The results from steps 2, 3, and 4 are input for compliance status and audit reports. Reports are available in the following: System Center Service Manager for manual control activities. In addition to centralized reports of automated controls, where input of the controls comes from other tools such as System Center Configuration Manager. The reports are based on the System Center Service Manager function of Incident or Change Management. System Center Configuration Manager for control activities in the previous step 3. System Center Operations Manager for control activities in step 4. The results from step 3 could be remediated automatically. The results of steps 2 and 4 must be considered and, if required, steps for remediation should be taken. How it works... The tool to use for control objectives and the corresponding control activities depends on the possible input and the required result of the control activity. The most basic questions that have to be answered are as follows: Does the control activity have a manual input/output? Is the control activity based on a query for system or application configuration status information? Is the control activity based on a query for monitoring/breaching status information? What type of control (manual or automated) and which characteristic of the control (preventive or detective) do you require? Based on the answers to those questions, it is possible to understand which System Center tool or Microsoft technology to use. Creating automated control activities within the System Center tools is but one task. The next steps must be as follows: Creating notifications or alerts for relevant stakeholders and reports Performing remediation Every System Center tool has its own reporting capability. This means there are different compliance reports in different System Center tools. To enhance usability, System Center Service Manager could be used to centralize most of those reports. Remediation for automated control activities, based on configuration settings, is the feature of System Center Configuration Manager. Depending on the requirements, after running a control activity compliance baseline that includes storing the results, all negative results of control activities could be remediated automatically. For auto-remediation based on monitoring or breach information, System Center Configuration Manager offers the capability to define actions. System Center Operations Manager offers the same capabilities. Each breach of a baseline could be auto-remediated out of the box. Regardless of the tool used, remediation must always be done in a documented fashion as this is a very common compliance requirement. In case a change is involved, the change management capabilities of System Center Service Manager should be used. All System Center tools create logs showing the action performed. There's more... Besides the already mentioned System Center tools, there are two more tools that belong to the core System Center product family. These are System Center Virtual Machine Manager and System Center Data Protection Manager. System Center 2012 R2 Virtual Machine Manager doesn't offer any compliance functionalities. It includes an audit log of administrator activities. This is a requirement in several regulatory requirements and therefore is quite useful. Out of the box, no additional benefits are provided. System Center 2012 R2 Data Protection Manager (SCDPM) is different. This tool is used for Backup and Disaster Recovery. These two topics are requirements in many standards and regulatory requirements. But there are already great books out there focusing on SCDPM, such as the following one: http://www.amazon.com/Microsoft-System-Center-Protection-Manager/dp/1849686300/ref=sr_1_1?ie=UTF8&qid=1403700777&sr=8-1&keywords=System+Center+Data+Protection+Manager Therefore, we have not included any recipes of SCDPM in this book. See also http://technet.microsoft.com/en-us/library/gg681958.aspx (the article in the Technet library on the planning of Compliance Settings in SCCM 2012) http://technet.microsoft.com/en-us/library/hh212740.aspx (planning of Audit Collection Service in SCOM 2012 in the Technet library) http://technet.microsoft.com/en-us/solutionaccelerators/cc835245.aspx (the article in the Technet library on the planning of compliance baselines in Security Compliance Manager) Planning the implementation of Microsoft System Center 2012 Service Manager Microsoft's System Center 2012 Service Manager (SCSM 2012) can be used to manage IT management processes (ITIL and MOF). The compliance management process is related to the IT management processes as well. Compliance issues can be handled as incident records; also, compliance related changes can be managed in SCSM 2012 as Change Requests. Getting ready Before we start planning the installation of SCSM 2012, you should be familiar with the ITIL or MOF management processes. Also, you should have planned the Incident and Change Management process for IT. How to do it... An example of the steps to plan the installation of the SCSM 2012 environment is as follows: Identify the required components of SCSM 2012. The SP1 or R2 version are also suitable. Identify the sizing of the SCSM 2012 infrastructure. Identify the amount of Configuration Items you want to have in the CMDB of SCSM 2012. How it works... For good performance in SCSM 2012, sizing and planning of the environment is essential. There is a Service Manager Sizing Helper tool available in the Service Manager job that aids documentation. You can download the SM_job_aids.zip file at http://go.microsoft.com/fwlink/p/?LinkID=232378. One sizing related factor is the amount of managed Configuration Items (CIs), for instance, managed users, computers, groups, printers, and other IT-related objects. Planning the numbers of CIs influences the sizing of the SCSM 2012 as well. There's more... The IT Governance, Risk and Compliance Management Pack (IT GRC MP) is not supported in SCSM 2012 R2. The last supported version is the Microsoft System Center 2012 SP1 Service Manager. See also http://www.itil-officialsite.com/ (IT Infrastructure Library) http://technet.microsoft.com/en-us/library/cc543224.aspx (Microsoft Operations Framework) http://technet.microsoft.com/en-us/library/hh519640.aspx (planning of SCSM 2012 in the Technet library) http://www.packtpub.com/microsoft-system-center-servicemanager-2012-cookbook/book (Microsoft System Center 2012 Service Manager Cookbook) http://www.microsoft.com/en-us/download/details.aspx?id=4953 (IT GRC Process Management Pack SP1 for System Center Service Manager) Planning and defining compliance reports The goal of compliance reports is to answer two things: "How am I doing" and "How effectively am I doing it" especially with regard to helping the business understand current and future threats. This recipe gives an overview on how to plan compliance reports. Getting ready Research the regulatory requirements using your country's respective laws, industry standards, and regulation. This will ensure your reports are relative only to your business and technical compliance objectives. For example, there are standards such as SOX section 404 that demand reports with certain criteria. How to do it... There are going to be at least two different types of reports you must plan for: Compliance status or audit reports Stakeholder-targeted reports Compliance status / audit reports Compliance status / audit reports are based on your controls. For these reports to answer the question about the actual compliance status and the effectiveness of the compliance program for your business, careful considerations have to be made as to which control activities will produce your business objectives. Therefore, the planning stage of these reports is already completed by the planning of your control objectives and their verification through control activities. With regard to System Center, out-of-the-box reports will be sufficient for many of these compliance status reports and audit reports. As mentioned in the Getting ready section of this recipe, be aware that several laws and industry standards demand certain formats for audit reports. In cases where the System Center out-of-the-box reports do not fulfill them, customized reports will have to be used. Stakeholder-targeted reports The purpose of these reports is to keep the stakeholder of your company informed about the compliance program. Therefore, the following questions must be answered: Who is the target audience of this report? What is your goal for this report? What input/output data can provide the required information? Who is responsible for the report (owner)? What is the frequency of the reports? How do you want to present this report? What is the improvement process on reports including data source input/output and controls? We will focus on the first question. You will have to consider reports for different levels such as the following: CEO and/or board members CISO and/or IT/Security team IT application owner Depending on the targeted audience of the report, different input/output values have to be used and sometimes, translation of inputs/outputs must be used. Using out-of-the-box reports from System Center tools will be possible for reports targeting IT application owners, CISO, the IT Security team, or the compliance team. Reports based on the analysis of certain control input/output data will either be accomplished using customized reports within System Center Service Manager or using additional tools such as System Center Orchestrator or dashboards. Regardless of the actual report, during the planning phase, several principles, that will increase the value of the reports to the business, should be followed. These principals are as follows: The overall report should be complete for its context The input of these reports should be consistently measured, at a low cost and preferably, as a number or percentage in context The output should be relevant The input and output should be transparent Complete Based on previous experience, compliance and IT security staff, while attempting to create reports, put in as much information and statistics as possible. In general, the report must be complete for the context it is designed for. So, on a CISO level, besides technical controls, manual controls including policy or process compliance may have to be included. Still, the report must be concise too. As a best practice, start out with the out-of-the-box reports provided by the System Center tools as they offer a large number of compliance reports. Measurable Being measurable is a key principle for creating valuable reports. The input and output data source or control should be measured in a consistent way. So, two different people using the same control at the same time should produce the same output. As much as possible, control should be automated to ensure this consistency and also to minimize cost. In case the control has to be done manually, it is essential that the people performing them do this in a consistent way. To accomplish this goal, each control should be documented; for example, there should be a document on the IT compliance for identity and access management. For the general users, one important document is the password policy, which should answer the questions why, what, how, and by whom. For IT people, there should be an additional document stating the technical implementation and automated or manual control, to ensure compliance with the password policy. In addition, it should mention how the control activity should be performed. In addition, whenever possible, controls used for reports should be expressed in numbers or percentage against a unit. For example, a control saying "10 systems out of 100 systems" have missing critical security updates, provides a clear value for a decision on what to do next, compared to a control with the value of "medium". Relevant This principle is important especially for the stakeholder-targeted reports. Reports should include controls or output that help the targeted audience in decision making. So the question of to whom the report will be provided is a decision factor on what to include and how to present the report. The IT security staff or compliance team requires the exact numbers of controls, for example, that 10 systems from 100 systems have missing critical security updates, whereas the IT application owner requires a drill down on which systems and security updates were missing. Transparent The target audience of a report must understand the controls or output used in the report. The labels should be plain and consistent; and clear measures for controls or input/output should be used. In addition, they must understand how these results came to be. This is especially true for indexes that comprise several controls. If this is the case, it should be clear as to which controls are included. If possible, indexes should be avoided as they average out the value presented in the report; for example, System Center Service Manager allows a report on incidents in the category under Security Compliance | System Security. The overall status of System Security may be green, as all controls besides the patch management control relating to critical security update did not report any issues. In case the affected systems hold sensitive information or are accessible by the public, this could be a factor in the decision process for immediate remediation steps. Understanding which controls are within the System Security category and being able to drill down into those controls or input/output used is important for a report. How it works... The focus is to give you an understanding of the type of reports you should consider and some basic considerations you should include in planning your reports. The first step is the planning of your control activities. If the control activities do not provide a measure of the effectiveness of your control objectives, then no report will be able to answer this question. Hence, qualified input/output controls are required. In this regard, the stakeholder of controls must provide input and sometimes must be included to improve processes or controls. Use the questions in this recipe to start out with the creation of your reports, but keep in mind that you have to adapt the information provided here to meet your business requirements and objectives. There's more... All System Center reports are based on the SQL Reporting service. This means you can create customized reports should the out-of-the-box reports provide the information you require. See also Detailed information on how to plan and implement reports based on System Center may be found in the book Security Metrics, Andrew Jaquith, Addison-Wesley Professional (http://www.amazon.com/Security-Metrics-Andrew-Jaquith-ebook/dp/B0050 G2RC8). Security Metrics is a book focusing more on effective measuring of IT security operations. It provides insights into implementing qualitative and meaningful data sources, ensuring reports that provide knowledge to help make the right strategic decisions. Look out for an upcoming cookbook by Sam Erskine from Packt Publishing. This book on System Center Reporting will provide detailed information on how to plan and implement reports based on System Center. Summary This article provided recipes on how to integrate the System Center products. The recipes use hands-on examples to show the required planning and implementation that must be made to align the System Center tools with the compliance process. Resources for Article: Further resources on this subject: VMware vCenter Operations Manager Essentials - Introduction to vCenter Operations Manager [Article] A Virtual Machine for a Virtual World [Article] An Introduction to Microsoft Remote Desktop Services and VDI [Article]
Read more
  • 0
  • 0
  • 1700
Packt
30 Oct 2014
7 min read
Save for later

concrete5 – Creating Blocks

Packt
30 Oct 2014
7 min read
In this article by Sufyan bin Uzayr, author of the book concrete5 for Developers, you will be introduced to concrete5. Basically, we will be talking about the creation of concrete5 blocks. (For more resources related to this topic, see here.) Creating a new block Creating a new block in concrete5 can be a daunting task for beginners, but once you get the hang of it, the process is pretty simple. For the sake of clarity, we will focus on the creation of a new block from scratch. If you already have some experience with block building in concrete5, you can skip the initial steps of this section. The steps to create a new block are as follows: First, create a new folder within your project's blocks folder. Ideally, the name of the folder should bear relevance to the actual purpose of the block. Thus, a slideshow block can be slide. Assuming that we are building a contact form block, let's name our block's folder contact. Next, you need to add a controller class to your block. Again, if you have some level of expertise with concrete5 development, you will already be aware of the meaning and purpose of the controller class. Basically, a controller is used to control the flow of an application, say, it can accept requests from the user, process them, and then prepare the data to present it in the result, and so on. For now, we need to create a file named controller.php in our block's folder. For the contact form block, this is how it is going to look (don't forget the PHP tags): class ContactBlockController extends BlockController {protected $btTable = 'btContact';/*** Used for internationalization (i18n).*/public function getBlockTypeDescription() {return t('Display a contact form.');}public function getBlockTypeName() {return t('Contact');}public function view() {// If the block is rendered}public function add() {// If the block is added to a page}public function edit() {// If the block instance is edited}} The preceding code is pretty simple and seems to have become the industry norm when it comes to block creation in concrete5. Basically, our class extends BlockController, which is responsible for installing the block, saving the data, and rendering templates. The name of the class should be the Camel Case version of the block handle, followed by BlockController. We also need to specify the name of the database table in which the block's data will be saved. More importantly, as you must have noticed, we have three separate functions: view(), add(), and edit(). The roles of these functions have been described earlier. Next, create three files within the block's folder: view.php, add.php, and edit.php (yes, the same names as the functions in our code). The names are self-explanatory: add.php will be used when a new block is added to a given page, edit.php will be used when an existing block is edited, and view.php jumps into action when users view blocks live on the page. Often, it becomes necessary to have more than one template file within a block. If so, you need to dynamically render templates in order to decide which one to use in a given situation. As discussed in the previous table, the BlockController class has a render($view) method that accepts a single parameter in the form of the template's filename. To do this from controller.php, we can use the code as follows: public function view() {if ($this->isPost()) {$this->render('block_pb_view');}} In the preceding example, the file named block_pb_view.php will be rendered instead of view.php. To reiterate, we should note that the render($view) method does not require the .php extension with its parameters. Now, it is time to display the contact form. The file in question is view.php, where we can put virtually any HTML or PHP code that suits our needs. For example, in order to display our contact form, we can hardcode the HTML markup or make use of Form Helper to display the HTML markup. Thus, a hardcoded version of our contact form might look as follows: <?php defined('C5_EXECUTE') or die("Access Denied.");global $c; ?><form method="post" action="<?php echo $this->action('contact_submit');?>"><label for="txtContactTitle">SampleLabel</label><input type="text" name="txtContactTitle" /><br /><br /><label for="taContactMessage"></label><textarea name="taContactMessage"></textarea><br /><br /><input type="submit" name="btnContactSubmit" /></form> Each time the block is displayed, the view() function from controller.php will be called. The action() method in the previous code generates URLs and verifies the submitted values each time a user inputs content in our contact form. Much like any other contact form, we now need to handle contact requests. The procedure is pretty simple and almost the same as what we will use in any other development environment. We need to verify that the request in question is a POST request and accordingly, call the $post variable. If not, we need to discard the entire request. We can also use the mail helper to send an e-mail to the website owner or administrator. Before our block can be fully functional, we need to add a database table because concrete5, much like most other CMSs in its league, tends to work with a database system. In order to add a database table, create a file named db.xml within the concerned block's folder. Thereafter, concrete5 will automatically parse this file and create a relevant table in the database for your block. For our previous contact form block, and for other basic block building purposes, this is how the db.xml file should look: <?xml version="1.0"?><schema version="0.3"><table name="btContact"><field name="bID" type="I"><key /><unsigned /></field></table></schema> You can make relevant changes in the preceding schema definitions to suit your needs. For instance, this is how the default YouTube block's db.xml file will look: <?xml version="1.0"?><schema version="0.3"><table name="btYouTube"><field name="bID" type="I"><key /><unsigned /></field><field name="title" type="C" size="255"></field><field name="videoURL" type="C" size="255"></field></table></schema> The preceding steps enumerate the process of creating your first block in concrete5. However, while you are now aware of the steps involved in the creation of blocks and can easily work with concrete5 blocks for the most part, there are certain additional details that you should be aware of if you are to utilize the block's functionality in concrete5 to its fullest abilities. The first and probably the most useful of such detail is validation of user inputs within blocks and forms. Summary In this article, we learned how to create our very first block in concrete5. Resources for Article: Further resources on this subject: Alfresco 3: Writing and Executing Scripts [Article] Integrating Moodle 2.0 with Alfresco to Manage Content for Business [Article] Alfresco 3 Business Solutions: Types of E-mail Integration [Article]
Read more
  • 0
  • 0
  • 10371

article-image-hosting-service-iis-using-tcp-protocol
Packt
30 Oct 2014
8 min read
Save for later

Hosting the service in IIS using the TCP protocol

Packt
30 Oct 2014
8 min read
In this article by Mike Liu, the author of WCF Multi-layer Services Development with Entity Framework, Fourth Edtion, we will learn how to create and host a service in IIS using the TCP protocol. (For more resources related to this topic, see here.) Hosting WCF services in IIS using the HTTP protocol gives the best interoperability to the service, because the HTTP protocol is supported everywhere today. However, sometimes interoperability might not be an issue. For example, the service may be invoked only within your network with all Microsoft clients only. In this case, hosting the service by using the TCP protocol might be a better solution. Benefits of hosting a WCF service using the TCP protocol Compared to HTTP, there are a few benefits in hosting a WCF service using the TCP protocol: It supports connection-based, stream-oriented delivery services with end-to-end error detection and correction It is the fastest WCF binding for scenarios that involve communication between different machines It supports duplex communication, so it can be used to implement duplex contracts It has a reliable data delivery capability (this is applied between two TCP/IP nodes and is not the same thing as WS-ReliableMessaging, which applies between endpoints) Preparing the folders and files First, we need to prepare the folders and files for the host application, just as we did for hosting the service using the HTTP protocol. We will use the previous HTTP hosting application as the base to create the new TCP hosting application: Create the folders: In Windows Explorer, create a new folder called HostIISTcp under C:SOAwithWCFandEFProjectsHelloWorld and a new subfolder called bin under the HostIISTcp folder. You should now have the following new folders: C:SOAwithWCFandEFProjectsHelloWorld HostIISTcp and a bin folder inside the HostIISTcp folder. Copy the files: Now, copy all the files from the HostIIS hosting application folder at C:SOAwithWCFandEFProjectsHelloWorldHostIIS to the new folder that we created at C:SOAwithWCFandEFProjectsHelloWorldHostIISTcp. Create the Visual Studio solution folder: To make it easier to be viewed and managed from the Visual Studio Solution Explorer, you can add a new solution folder, HostIISTcp, to the solution and add the Web.config file to this folder. Add another new solution folder, bin, under HostIISTcp and add the HelloWorldService.dll and HelloWorldService.pdb files under this bin folder. Add the following post-build events to the HelloWorldService project, so next time, all the files will be copied automatically when the service project is built: xcopy "$(AssemblyName).dll" "C:SOAwithWCFandEFProjectsHelloWorldHostIISTcpbin" /Y xcopy "$(AssemblyName).pdb" "C:SOAwithWCFandEFProjectsHelloWorldHostIISTcpbin" /Y Modify the Web.config file: The Web.config file that we have copied from HostIIS is using the default basicHttpBinding as the service binding. To make our service use the TCP binding, we need to change the binding to TCP and add a TCP base address. Open the Web.config file and add the following node to it under the <system.serviceModel> node: <services> <service name="HelloWorldService.HelloWorldService">    <endpoint address="" binding="netTcpBinding"    contract="HelloWorldService.IHelloWorldService"/>    <host>      <baseAddresses>        <add baseAddress=        "net.tcp://localhost/HelloWorldServiceTcp/"/>      </baseAddresses>    </host> </service> </services> In this new services node, we have defined one service called HelloWorldService.HelloWorldService. The base address of this service is net.tcp://localhost/HelloWorldServiceTcp/. Remember, we have defined the host activation relative address as ./HelloWorldService.svc, so we can invoke this service from the client application with the following URL: http://localhost/HelloWorldServiceTcp/HelloWorldService.svc. For the file-less WCF activation, if no endpoint is defined explicitly, HTTP and HTTPS endpoints will be defined by default. In this example, we would like to expose only one TCP endpoint, so we have added an endpoint explicitly (as soon as this endpoint is added explicitly, the default endpoints will not be added). If you don't add this TCP endpoint explicitly here, the TCP client that we will create in the next section will still work, but on the client config file you will see three endpoints instead of one and you will have to specify which endpoint you are using in the client program. The following is the full content of the Web.config file: <?xml version="1.0"?> <!-- For more information on how to configure your ASP.NET application, please visit http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <system.web>    <compilation debug="true" targetFramework="4.5"/>    <httpRuntime targetFramework="4.5" /> </system.web>   <system.serviceModel>    <serviceHostingEnvironment >      <serviceActivations>        <add factory="System.ServiceModel.Activation.ServiceHostFactory"          relativeAddress="./HelloWorldService.svc"          service="HelloWorldService.HelloWorldService"/>      </serviceActivations>    </serviceHostingEnvironment>      <behaviors>      <serviceBehaviors>        <behavior>          <serviceMetadata httpGetEnabled="true"/>        </behavior>      </serviceBehaviors>    </behaviors>    <services>      <service name="HelloWorldService.HelloWorldService">        <endpoint address="" binding="netTcpBinding"         contract="HelloWorldService.IHelloWorldService"/>        <host>          <baseAddresses>            <add baseAddress=            "net.tcp://localhost/HelloWorldServiceTcp/"/>          </baseAddresses>        </host>      </service>    </services> </system.serviceModel>   </configuration> Enabling the TCP WCF activation for the host machine By default, the TCP WCF activation service is not enabled on your machine. This means your IIS server won't be able to host a WCF service with the TCP protocol. You can follow these steps to enable the TCP activation for WCF services: Go to Control Panel | Programs | Turn Windows features on or off. Expand the Microsoft .Net Framework 3.5.1 node on Windows 7 or .Net Framework 4.5 Advanced Services on Windows 8. Check the checkbox for Windows Communication Foundation Non-HTTP Activation on Windows 7 or TCP Activation on Windows 8. The following screenshot depicts the options required to enable WCF activation on Windows 7: The following screenshot depicts the options required to enable TCP WCF activation on Windows 8: Repair the .NET Framework: After you have turned on the TCP WCF activation, you have to repair .NET. Just go to Control Panel, click on Uninstall a Program, select Microsoft .NET Framework 4.5.1, and then click on Repair. Creating the IIS application Next, we need to create an IIS application named HelloWorldServiceTcp to host the WCF service, using the TCP protocol. Follow these steps to create this application in IIS: Open IIS Manager. Add a new IIS application, HelloWorldServiceTcp, pointing to the HostIISTcp physical folder under your project's folder. Choose DefaultAppPool as the application pool for the new application. Again, make sure your default app pool is a .NET 4.0.30319 application pool. Enable the TCP protocol for the application. Right-click on HelloWorldServiceTcp, select Manage Application | Advanced Settings, and then add net.tcp to Enabled Protocols. Make sure you use all lowercase letters and separate it from the existing HTTP protocol with a comma. Now the service is hosted in IIS using the TCP protocol. To view the WSDL of the service, browse to http://localhost/HelloWorldServiceTcp/HelloWorldService.svc and you should see the service description and a link to the WSDL of the service. Testing the WCF service hosted in IIS using the TCP protocol Now, we have the service hosted in IIS using the TCP protocol; let's create a new test client to test it: Add a new console application project to the solution, named HelloWorldClientTcp. Add a reference to System.ServiceModel in the new project. Add a service reference to the WCF service in the new project, naming the reference HelloWorldServiceRef and use the URL http://localhost/HelloWorldServiceTcp/HelloWorldService.svc?wsdl. You can still use the SvcUtil.exe command-line tool to generate the proxy and config files for the service hosted with TCP, just as we did in previous sections. Actually, behind the scenes Visual Studio is also calling SvcUtil.exe to generate the proxy and config files. Add the following code to the Main method of the new project: var client = new HelloWorldServiceRef.HelloWorldServiceClient (); Console.WriteLine(client.GetMessage("Mike Liu")); Finally, set the new project as the startup project. Now, if you run the program, you will get the same result as before; however, this time the service is hosted in IIS using the TCP protocol. Summary In this article, we created and tested an IIS application to host the service with the TCP protocol. Resources for Article: Further resources on this subject: Microsoft WCF Hosting and Configuration [Article] Testing and Debugging Windows Workflow Foundation 4.0 (WF) Program [Article] Applying LINQ to Entities to a WCF Service [Article]
Read more
  • 0
  • 0
  • 17467
Modal Close icon
Modal Close icon