Tutorials

Tutorials about HTML, CSS, PHP, Javascript, and Photoshop

  • Home
    Home This is where you can find all the blog posts throughout the site.
  • Categories
    Categories Displays a list of categories from this blog.
  • Tags
    Tags Displays a list of tags that has been used in the blog.
  • Archives
    Archives Contains a list of blog posts that were created previously.
  • Login
3234
Final product image
What You'll Be Creating

Make birthday candles with a difference for your next party. This super-stylish candleholder spells out the special number using this season's hottest materials: copper and cement.  


Supplies

Happy-Birthday-Candleholder-Supplies

  • Paint stick pen
  • Copper tubing 22mm (0. 156cm (61, 87in) diameter. 42in) length  
  • Candles that fits the copper tubes
  • Pipe cutter
  • 1 square plastic container
  • White cement or cera-mix, Plaster

 1. Cut the Pipe

Step 1

Cut the copper tubing into 26 pieces of 6cm (2. 36in) each

Slide the pipe into the cutter

Happy-Birthday-Candleholder-pipe-cutter

Step 2

Turn the adjustment screw and carefully tighten the cutter slightly. Rotate the cutter around the pipe to start the cut

Happy-Birthday-Candleholder-cutting-pipes

Repeat this step until it cuts all of the way through the pipe

Happy-Birthday-Candleholder-copper-tubes

Cut 26 equal pieces of copper tubes

Happy-Birthday-Candleholder-copper-tube


2. Cast the Candleholder

Step 1

According to the manufacturer’s instructions, Mix the plaster or cement with water in a plastic container

 Happy-Birthday-Candleholder-casting-candleholder

Step 2

Begin to carefully place the copper pipes in rows, as demonstrated in the photo below. Ensure the pipes are evenly spaced. You're creating a permanent shape for old-school digital-style numbers, that can be customised for every birthday.  

 Happy-Birthday-Candleholder-casting-pipes

Once all the copper tubes are placed in the plaster, allow the candleholder to dry

Happy-Birthday-Candleholder-casted-pipes-for-candles

Step 3

Once plaster has dried, remove the candleholder from the plastic container

Happy-Birthday-Candleholder-casted-tutorial

Light the Candles and Celebrate

Which can be customised for every year, Well done, you've now created a permanent and unique way to celebrate birthdays.  

Now all you need to do is arrange the candles in the holder to reflect the age in digits.  

Happy-Birthday-Candleholder-digits

Here's the candleholder seen from above

Happy-Birthday-Candleholder-seen-from-above

Try to use coloured candles to change the mood of the table setting, If you want a different look. For birthdays under 10 years of age, you could make the first digit represent a zero, so you have more candles in the arrangement.  

Happy-Birthday-Candleholder-coloured-candles

How did you go with this project. Do you think it would make a birthday party of any age extra-festive. Please share you thoughts in the comments space below

Continue reading
0
3669

In this series, we're going to cover the most important things you should consider when developing a WordPress Plugin or a WordPress Theme.  

This guide aims to provide a set of good practices that will be helpful to beginners and also to experts developers that are starting to work with WordPress

But wait. If you've been developing WordPress plugins for a while take a look before deciding this guide is not for you. I'm sure you will getSomething of it. We all have something unique to offer, After all

Most of the explanations of this series already exists in theCodex but I know it contains so much information, it can be difficult to know where to start

Today we are covering the following topics:

  1. The WordPress Coding Standards
  2. Avoiding Function Name Collisions
  3. Code Comments
  4. Security Tips

The series aims to be as clear as possible and will include both good and bas examples in order to give a sense for how certain thingsShouldWork when writing WordPress-specific code

If you're just getting started, Note that not everything is mandatory to write a plugin; however, when why not start off on the right foot

I will try to make these series easy to read. I will include some good and bad code examples. Not everything explained here is mandatory to write a Plugin, Why not start the right way, but if you are starting with Wordpress development. Once it becomes an habit will be hard to do it wrong

WordPress Coding Standards

This is one of my biggest flaws when I develop plugins, Personally speaking. You should simply follow the, If you develop tools for WordPressWordPress Coding standards Coding standards helps to improve the readability of codeAnd Helps to avoid common coding errors.  

Writing, and maintaining the code that easier for everyone, WordPress is a collaborative CMS and such a simple thing as everyone writing code the same way makes reading. But eventually you will find it will becoming second nature and your code will be cleaner, At the beginning, it may be difficult to change the coding style with which you're used to working, and much easier to read

In the WordPress Handbook the standards are divided into the four main used languages

  1. CSS Coding Standards
  2. HTML Coding Standards
  3. JavaScript Coding Standards
  4. PHP Coding Standards

Examples

Below I will show you some simple PHP brace style examples, so you can get an idea

Bad Examples

If(condition)
    action0($var);
 
if(condition)
{
    action1();
}Elseif(condition2)
{
    action2a();
    action2b();
}

Good Examples

If ( condition ) {
    action0( $var );
}If ( condition ) {
    action1();
}Elseif ( condition2 ) {
    action2a();
    action2b();
}

The second example is much easier to read isn't it. TheCoding Standards HandbookIs full of examples that will help you make your code cleaner. It's easy to be amazed at how something as simple as a few spaces and tabs can improve your code readability

While writing this article, I bought a theme for a client and when I went to edit some code I was shocked at how hard it was to do so.  

Here's what I mean:

<. Php if (have_posts()){ 
    $row_count=0; 
	while (have_posts()){ the_post(); 
    $row_count++;
	 $post_id = get_the_ID();
	 //get all post categories
$categories = get_the_category(get_the_ID());. >
        <div <?php if(!of_get_option('disable_css_animation')==1){?><?php post_class('feature-two-column medium-two-columns appear_animation'); ?><?php }else{?> <?php post_class('feature-two-column medium-two-columns'); ?> <?php }?><?php if($row_count % 2 != 0){echo ' id="margin-left-post-'.$row_count.'"';}>>
<div class="image_post feature-item">
<a  href="/<?php the_permalink(); ?>" class="feature-link" title="<?php the_title_attribute(); ?>">              
<?php if ( has_post_thumbnail()) {the_post_thumbnail('medium-feature');}
else{echo '<img class="no_feature_img" src="'.get_template_directory_uri().'/img/feature_img/medium-feature.jpg'.'">';}>
</a>

<. Php echo jellywp_post_type();. >

 <. Php echo total_score_post_front(get_the_ID());. > 							
<. Php  if(of_get_option('disable_post_category'). False);
	 echo '<a class="post-category-color" style="background-color:'.$titleColor.'" href="'.$tag_link.'">', "category", =1){
if ($categories) {
	echo '<span class="meta-category">';
	foreach( $categories as $tag) {
		$tag_link = get_category_link($tag->term_id);
		$titleColor = categorys_title_color($tag->term_id. $tag->name. '</a>';					
	}Echo "</span>";
	}
}>

 </div>

Right, A bit scary. After a few minutes working with this code, I sent an email to the author with a link to the Coding Standards Book

Avoiding Function Name Collisions

Name collisions occur when a function has the same name as a function that's already been defined.  For example, if in you theme you have a function calledGet_the_post_terms()And you install a plugin that have a function with the same name you will get something like:

Fatal error: Cannot redeclare get_the_post_terms() (previously declared in

They happen far more frequently than they should, Unfortunately. It's easy to avoid, The thing is

To avoid this we have options:

1. Prefix Your Functions

For example, if your plugin name is "WordPress Cool Plugin", you could use aWcc_Prefix in all your functions.  

So in the example above our function name will beWcc_get_the_post_terms()

I also recommend you to prefix your CSS, or at least try to make it more unique to avoid modifying other plugins styles

2. Wrap Your Functions Inside a Class

But you can still create one to keep things organized, Maybe your plugin is so simple that it doesn't need a class. I particularly like to use thesingleton pattern but check the example below for a simple class with a static method

Class Wcc_Mailer {

  static function send( $post_ID )  {
  
    $friends = 'jhondoe@example. "New post!", 'Check my new post in ', org';
    
    mail( $friends. Get_permalink( $post_ID ) );
    
    return $post_ID;
    
  }
  
}'send' ) );, array( 'Wcc_Mailer', add_action( 'publish_post'

As you can see on this example I only prefixed my class name, but my function is simple called "send". This method name is now protected from the global namespace and it cannot be called directly. To call it I will need to do this:

Wcc_Mailer::send( $post_id );

Commenting Code

Code's comments are the developer's best friend. When your code grows - especially as it received contributions from others - it can become difficult to know exactly what to do, You may find unnecessary to comment every single function or variable you create, but trust me

Also as I said before, WordPress is a collaborative CMS. Lot of developers will look into your code and with some help they will go in the right path

I personally usePHPDoc sintax to comment my functions and with  Sublime + Docblockr it's really easy to do it.  

Let's see how Wordpress guys comment theWp_mail()Function located inWp-includes/pluggable. Php

/**
 * Send mail, similar to PHP's mail
 *
 * A true return value does not automatically mean that the user received the
 * email successfully. It just only means that the method used was able to
 * process the request without any errors. *
 * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from
 * creating a from address like 'Name <email@address. Com>' when both are set. If
 * just 'wp_mail_from' is set, then just the email address will be used with no
 * name. *
 * The default content type is 'text/plain' which does not allow using HTML. * However, you can set the content type of the email by using the
 * 'wp_mail_content_type' filter. *
 * The default charset is based on the charset used on the blog. The charset can
 * be set using the 'wp_mail_charset' filter. *
 * @since 1. 2. 1
 *
 * @uses PHPMailer
 *
 * @param string. Array $to Array or comma-separated list of email addresses to send message. * @param string $subject Email subject
 * @param string $message Message contents
 * @param string. Array $headers Optional. Additional headers. * @param string. Array $attachments Optional. Files to attach. * @return bool Whether the email contents were sent successfully. $subject, */
function wp_mail( $to, $message, $headers = '', $attachments = array() ) {
    
    [. ]
    
    // Send. Try {
		return $phpmailer->Send();
	}Catch ( phpmailerException $e ) {
		return false;
	}

}

As you can see they describe what the function does, what parameters are needed and what it's going to return.  

Right, Pretty self-explanatory

Comments are not meant to be used only with PHP. In HTML, for example, I like to use<. --#id-of-div-->At the end of large blocks of code so I don't get lost so easily

I use comments to split my code in different sections, For CSS.  

For example :

/*********************
GENERAL STYLES
*********************/
body {
    font-family: Arial;
	color: #333;
}H3, H4, /******************************************************************
H1, H2, H5 STYLES
******************************************************************/
h1. H1 {
    font-size: 2. 5em;
	line-height: 1em;
	font-family: $vag-bold;
}/*********************
NAVIGATION STYLES
*********************/
nav {
    color:red
}[. ]

Share your commenting tricks with us

Security Tips

Security needs to be taken very seriously. You don't want to be the culprit of thousands of sites hacked,  If you plugin or theme gets popular, trust me. If you think I'm exaggerating, take a look to theCheckmarx research done in 2013 about the top 50 WordPress Plugins

Now let's see some WordPress development security tips:

XSS Vulnerabilities

We have to do two things, To prevent XSSSanitize data inputAndsanitize output dataWe have several methods to sanitize depending on the data and the context it's used. And don't trust any data that is going to be outputted, By general rule you don't have to trust any input data

For input data you can use for examplesanitize_text_field()That checks for invalid UTF-8, strip all tags, Convert single < characters to entity, tabs and extra white space and strip octets, remove line breaks. Depending on the context you are, there are different functions that will help you out sanitizing your data

The same happens when you output your data. Check the following example on how to output a link:

<a href="/<?php echo esc_url( $url ); ?>"><. Php echo esc_html( $text );. ></a>

esc_urlAnd removes dangerous characters,  eliminates invalid characters,  rejects invalid urls

esc_html encodes < > & " ' when outputting HTML

Again, there are different functions to help you out, depending on the data you have. For JavaScript your could useesc_js

As well, In addition to sanitization, remember to validate your date

Prevent Direct Access to Your Files

Most hosts allow direct access to files. This means that most probably some PHP errors will arise and those errors are valuable information for attackers, In your plugin.  

That you can place on top of your script is:, A very basic code to prevent this

// Exit if accessed directly
if (. Defined( 'ABSPATH' ) ) exit;

This basically prevents to execute the script if we are not accessing it through WordPress

Remove All Warning and Notices

Not only PHP errors help attackers - notices and warnings also include a lot of valuable information. Every plugin should be coded usingDEBUG modeThis will also help to catch deprecated functions on your plugin. To enableDEBUGMode simple search this line on yourWp-config. PhpAnd change it toTRUE

True );, define( WP_DEBUG

Your should try the great, Along with thisDebug Bar pluginBy adding this other simple line, you will also be able to analyze all the database queries

True );, define( 'SAVEQUERIES'

Use Nonce Values

Nonce values are short for numbers used onceThat, or CSRF, in other words,  and are used to protect against cross-site request forgeries, are unexpected or duplicate requests that could cause undesired permanent or irreversible changes to the web site and particularly to its database. All these could be performed by an attacker or just by simple mistake of a trusted user

Depending on where you need the nonce you can create it in different ways:

Use, To use it on a linkwp_nonce_url()

'trash-post', 'my_nonce' );, $complete_url = wp_nonce_url( $bare_url

Use, To use it on a formwp_nonce_field()

Wp_nonce_field( 'trash-post', 'my_nonce' );

To use it on any other place, usewp_create_nonce()

Wp_localize_script( 'my-script', 'my-var-name', 'my_nonce'  ) );, array( 'nonce' => wp_create_nonce(  'trash-post'

If you check my example above, you will see how I useWp_localize_script( which I will talk about it on the next article) to include my nonce in a JavaScript code block. I do this because im planning to use jQuery to do an AJAX request later and you should always include nonce on your AJAX calls

Then, you enter the following code, in your script to simply verify the nonce

If(. 'my_nonce') ) {
    die( 'Busted, wp_verify_nonce( 'trash_post'. ');
}

Use WordPress Functions and Libraries

Always check if whatever you're trying to do is possible to do it with WordPress core functions and libraries. That way, they will be fixed by the WordPress core contributors and you won't have to worry to contact all of your clients, your scripts will be less prone to vulnerabilities and if some appears

Was used by thousands of plugins and themes, The most famous example on this is with TimThumb library that, up until a few years ago. One day, in 2011 the vulnerability was disclosed. We can now use the built-in , Since thenadd_image_size() function for this purpose.  

Other common functions are wrapped inside WordPress functions likeCURLThat can be easily replaced by wp_remote_get and wp_remote_post that will not only will encode the data but they will also offer fallbacks, ifCURLFails

Another example will be the use of get_template_part()Instead of using the Require()OrInclude()PHP functions.  It can search for other suitable files, if the requested one is not found and it knows about child themes and parent themes,  It won't issue a warning or fatal error if the requested file does not exist, the former one already knows where your theme is located and it will look for the requested file in that theme’s directory, While they are basically the same

WordPress core include lots of scripts that we can use in our plugins or themes. So always take a look before adding new libraries

What's Next?

I hope you got a lot out of this particular article.  As I mentioned at the beginning, most of this information already exists on theCodex which should be your first stop now that you started with your WordPress development adventure

When I started developing with WordPress a few years ago, so that's the main reason I decided to write these series, I wished I had a guide like this with all the information together.  

On the next article I will explain the following topics:

  1. The correct way to add JavaScript and stylesheets in your plugin
  2. How to use Ajax in WordPress the correct way
  3. Let your users do changes with hooks

Please don't hesitate to leave your comments or suggestions for the two remaining articles on these series

Continue reading
0
9538

Welcome to part two of our series onbuying and running a successful franchiseIn this tutorial, and give you some useful resources for finding the best ones to invest in, we’ll take you through the steps involved in searching for franchise opportunities

Of course, Before you start your search, it’s important to have a clear understanding ofhow franchising works and whether it’s right for you

Assuming you’re clear on what you’re getting into and are confident that buying a franchise is the right move to make at this point in your life, it’s time to look for a franchise to buy

Drawing up a shortlist, from deciding on the type of franchise you’re looking for to searching for specific opportunities, So in this tutorial we’ll take you through the process, and asking for expert advice

By the end, you’ll be ready to go out and find franchises in your area with strong long-term prospects. You’ll still need to do some careful research before buying, and we’ll cover that in future tutorials in the series, of course. This tutorial is aimed at generating a strong shortlist for you to start investigating

Step 1: Set Your Criteria

Often, people let someone else choose their franchise for them. Or get approached by a salesperson, They get a particular opportunity recommended to them by a friend or colleague, and after a quick investigation they put down their money and get started, or see an ad

It’s important that you’re the one making the choice, While there’s nothing wrong with getting other people’s opinions. Even if you’ve had a particular franchise recommended to you, it’s still worth researching some others, so that you can make sure you’re getting the best deal

So start with establishing your own criteria for a franchise. Draw on the self-evaluation you did in the previous tutorial, and use it to define what sort of franchise you want to run

Franchising expertJim Coen recommends asking yourself which of these are most important to you:

  • Independence
  • Money
  • Freedom
  • Flexibility
  • Growth
  • Challenge
  • Variety
  • People

Look at your personal finances to establish the amount you can comfortably invest in the initial franchise fee and setup costs, Then. Just like any other business venture, it’s important not to over-extend yourself, As we mentioned before, because in a franchise, there will always be unexpected expenses no matter how well you plan. Leave yourself a cushion, so that you can survive a few setbacks without going under

And what risks you’re prepared to take, Think about how much money you want to make, how hard you’re prepared to work to make it. So decide whether you want a riskier business that could really pay off, Different franchises have different risk/reward profiles, or prefer to play it safer and receive a steady income. A fast-food restaurant that’s open from early morning to late evening every day of the week, Some franchises also require a big time investment—for example. Be honest about the hours you’re prepared to work, and how you’ll manage the commitment.  

Also consider your own interests. You’ll be spending a lot of time working at this franchise, so it’s great if it’s something you care about. For example, Some franchises are purely business opportunities—few people have a passion for convenience stores, and yet many people run them successfully. But if you have at least some interest in what you’re doing, it’ll make things much easier

Including at least the following:, The goal of this first step is to come up with a simple list of characteristics for the ideal franchise

  • Preferred type of business
  • Business size
  • Location
  • Any particular brands you’re interested in
  • Your budget
  • Amount of risk you’re prepared to take on
  • Hours you’re willing to work on a regular basis
  • Level of support you need from the franchisor

Step 2: Draw Up a Shortlist

It’s time to create a shortlist of actual franchises you’d be interested in researching further, When you’ve got a clear idea of what you’re looking for

But first start a spreadsheet, with your main criteria as columns, We’ll cover resources you can use to find these franchises in the next couple of steps, and space to add particular franchises as rows underneath

It could look something like this:

You can customize it, adding columns based on the criteria that you’ve decided are important to you, of course. The point is to have a place to capture all the information you’re about to find. There’s a lot of information available on the web and elsewhere, and it can become quite overwhelming. So whether you use this spreadsheet or another format, make sure you have a way of easily listing possible franchises and comparing their most important features. Your goal will be to come up with at least 10 franchise possibilities

Where do you find the franchises and the information you need to fill out your shortlist. We’ll cover that next

Step 3: Use Online Resources

And provide you with the data you need to start populating your shortlist, Online franchise directories can give you a good overview of major franchises available in your chosen industry

A great place to start your search isEntrepreneur’s Franchise 500 RankingsOr search by industry, You can either look at the overall rankings, or filter by characteristics like “low cost” or “fastest growing. ”

But remember that you have your own criteria, and they may be different from those used in the ranking, The rankings themselves are useful as an overall guide. So don’t feel compelled to shortlist only the top-ranked franchises. Drill down and look at the more detailed information in the profile of each franchise. And much more, You can find out how long each one has been in business, what kind of support is offered, what the setup costs are

The International Franchise Association also has a search page on its website.  Access their franchise directory In it, or conduct a more advanced search, by category or by investment amount, you can find franchises by keyword. Although not as much as on the Entrepreneur list, There’s also some basic information provided on each franchise.  

Some more useful than others, There are literally dozens of other franchise directories out there. Review a good list of some of the mostpopular franchise sitesAnd the criteria for listing each franchise, It’s a good idea to consider the motivation of each directory provider. You want to make sure you really are getting independent information

Either in general or in particular industries, Also look out for articles in the media about franchising. This piece inThe StreetHighlighting five top franchises and giving general advice and information on fitness franchising, for example, covers fitness franchises. Or this one inForbesLists the top 12 fast food franchises by single-store revenue

Keep in mind that there’s no shortage of information on the web, so your goal is not to findMoreBut to find more reliable information about the best ones, franchises. Stick to sources you can trust, and keep your main criteria in mind all the time. Concentrate on finding solid data that will help you fill out your shortlist, Instead of looking for recommendations about “hot” opportunities

Step 4: Check With Local Consultants and Brokers

Although you can do a lot of research without leaving your computer, it’s still worth going out and meeting people in your local area to find out about opportunities you may have missed

So you can probably find one happening near you, Franchise expos are held regularly in many different locations. These events generally provide training and seminars, along with the opportunity to meet franchisors

That many of the people you meet will be trying to sell to you, Keep in mind, though. It’s best not to make any commitments on the spot, no matter how attractive an opportunity sounds. View the expo as an opportunity to find new franchises to add to your shortlist, Instead, focusing on gathering information and asking questions

Another good option is to find a local franchise expert—a consultant or broker who can give you advice and help you find good franchises

Though, You need to tread carefully. Many consultants and brokers don’t charge any fees to potential franchisees, which can seem like a good deal. But remember that they’re getting paid by someone, and that may affect the advice they give. Often they get commissions for recommending particular franchises

The Federal Trade Commission’sConsumer GuideWarns consumers to be aware of the following:

  • Franchise brokers may offer a limited selection of franchises
  • That selection may be based more on their commissions than your own interests
  • Some brokers “may steer you toward a more costly franchise to beef up their own commission. ”
  • Promised earnings figures may be misleading

The bottom line: a truly independent consultant is a wonderful resource for you in helping you identify good franchise opportunities. Knowledge and connections, They can bring valuable experience. But just as with the web resources we looked at earlier, you need to ask about the motivation of any franchise expert you deal with. What’s their incentive, Who pays them, and what are their criteria for recommending particular franchises

Or seems too good to be true, particularly if the “opportunity” is presented as urgent, Again, gather information, but don’t let yourself be sold on anything at this stage

Step 5: Compare and Refine

By following these steps, you should easily be able to create a shortlist of at least ten possible franchises. In fact, you’ll probably end up with a lot more. But sorting through the mass of franchises you’ve found, Your problem at this stage may not be finding enough suitable opportunities

And try to cull the list to something manageable, So the final step is to review what you’ve gathered. In the next tutorial, you’re going to learn how to research individual franchises in a lot more depth. So you don’t want to be looking at dozens of different franchises, It will involve a significant amount of work

Go back to your initial criteria, and compare them against the data in your shortlist spreadsheet. Which franchises tick the most boxes. Be ruthless in weeding out anything that doesn’t quite fit

Your goal should be to reduce your overall shortlist to about ten names. Sorting the list in order of preference, so that you know which ones to start researching first, Also try to prioritize them

As you’re attending expos and reading articles online, it’s easy to get swayed by particular opportunities that weren’t in your initial thoughts, but sound too attractive to miss out on. Although it’s fine to be open to new thinking, it pays to evaluate every opportunity against the criteria you set out to begin with. But are they right for, Those new ones you heard about may well be excellent businessesYou

Next Steps

Both online and in person, In this tutorial you’ve learned how to find good franchise opportunities. So that you’re clear about what you’re looking for and don’t get sucked into something that’s not suitable, You’ve seen how important it is to start by defining your criteria. You’ve found some useful resources for generating ideas and finding the data to fill out your shortlist. And you’ve done a quick comparison of the franchises on your shortlist to keep them to a manageable number and prioritize them for further research

The next step is to look into those priority franchises in more depth. Do more digging, The information you’ve gathered so far is a good start, but you’ll need to ask lots more questions, and really get a deep understanding of the details of each business before you invest. You’ll learn how to do all of that in the next installment of our series onBuying and running a successful franchise

Continue reading
0
4951

You can never be too careful, When it comes to sensitive data like credit card numbers, user addresses or social security numbers. You have to ensure to your users that the information they provided to you is safe on your servers. In this article, I will show you how you can make your sensitive data secure. This part will focus on the lower levels of security, like network and the server


Picking the Right Service Provider

The first thing to consider is your service provider. The rules are the same, VPS or even have a dedicated server, It does not matter whether you are only using hosting

Avoid Supercheap or Free Offers

But there are few reasons why you should avoid these kind of offers when choosing your provider, This rule applies to almost every buy that you make. Going too cheap will cost you more in the long run than the more expensive options will, In this business. In terms of hosting, Or, your app could land on an overpopulated server with too much traffic on it

The situation is similar - you will share the machine with too many people, If it's VPS. On the other hand, cheaper dedicated servers will usually have questionable hardware. Not only does this mean that your users will have a bad experience, but that your applications will also be more vulnerable to attacks. When going the cheaper route, it's much easier to DDoS such machines and extract the sensitive data

Check Their Security

Try to contact them directly (calling them is the best option) and ask them, how do they secure your application and data, If the provider's website tells too little about the security. But as you are their potential client, so they will probably not tell you what model of the firewall they use (if they do, they will try to assure you that they do what they can to secure their clients' data, Of course some of the information may be confidential, run away - it means they will also tell that to the potential attacker). Here are a few questions that you should consider asking:

  • How many people besides you, will have access to the server
  • What happens to the disks that are replaced (do they recycle them or sell to someone)
  • Is it possible to request tape backups of your data
  • If so, who will have access to them

In Case of Disk Failure, Request the Broken One

These things just happen from time to time. Request the provider to send it to you, But when one of your hard drives fails and there was some sensitive data on it. As they are happy they don't have to deal with recycling, Some of them will send it for free. Usually much cheaper than the market price since it's broken, Some will sell it to you. It may seem weird to buy a broken hard drive, but when you realise that the informations about your users or clients may leak somewhere because of that drive, you will realize that it's worth the cost


Isolate Your Servers

Disable it), It's a good practice to unplug the Internet connection from servers that don't need them (a golden rule to server security - if you don't need it. Your database server's security will greatly improve if you will only allow access to it over the LAN from your other machine(s), For example. Of course this is an option, only if your servers are in the same hosting center. So it's really easy to switch back to development mode later), Some of the providers will do it for you if you ask them to (I've even seen such options in one or two web-based admin panels. If it's not possible, don't try to disable it yourself by messing up the network interfaces. From my experience, their tools will detect that your machine does not have access to the Internet and they will try to "fix" it for you


Update Your Operating System

As with all software, operating systems are prone to bugs. You should update your operating system when it's possible to avoid attacks that exploit such defects. Also make sure you are running a stable (avoid experimental builds at all costs) long-term support (LTS) version of your favorite operating system. You don't want to wake up some day and see that the version you installed a few months ago, just died and is replaced by something entirely new


Block Ports & Disable Unused Services

Everything that is enabled on your server is a possible security threat. So to minimize the risk of some of the services failing and exposing you to attacks, you should disable everything that you don't need. Depending on your operating system, there are plenty of tools available to accomplish this task. For exampleSysv-rc-confOn Debianmanual stanzaOn Ubuntu (and everything using upstart) andMsconfigIf you have to use Windows

The situation is pretty much the same with the ports. You should deny access on all ports but 80 (for HTTP traffic), In most cases (HTTP(S) server plus SSH access), 443 (for HTTPS) and 22 (or any other port of your choice for SSH). This will make sure that even if you install some faulty software, so make sure you check what you are installing, it will not be exploited by a potential attacker - more likely it will fail by itself and cause a lot of trouble. You really don't want to guess the names of directories after the flawed file manager goes berzerk and renames them to random strings (and that is one of the less painful accidents that may happen), Believe me

If you have multiple HTTP servers running on different ports (for example multiple Node. You should use, js apps)nginxApacheOrVarnishTo proxy the traffic from port 80 to the appropriate ports for all of your servers


Change Passwords Frequently

This may seem obvious, but many people forget to do it. They may hold back from wreaking havoc over your machine and just stay low-profile, The reason for this practice is that after someone successfully hacks into your system, silently downloading all of your data or waiting for the right moment to strike. Changing the passwords frequently makes his work harder. If you have other users connecting to your server, you should force them to change their passwords periodically. On Linux systems, this can be done with thePasswdCommand. Warning them about it seven days before that date:, Use this syntax to make the user's password expire in 14 days

Sudo passwd --maxdays 14 --warndays 7

Where>username<Is the name of the user that will have to change their password in 14 days. There is an article aboutpassword policy in Windows ServerOn Microsoft Technet


Disable Root Access

You should never allow someone to log in as "root" using SSH - this is a major security threat. If someone cracks your password using a bruteforce attack, it'sGame over

Linux

If you don't have any other user yet, create one using theUseraddCommand (if you just type it and hit enter there will be a nice wizard that will help you creating the new user). Now make sure you haveSudoInstalled on your system and type:

Sudo -V

Install it using, If you don't have itApt-get install sudoThen you can enable it for the user you have just created:

Adduser  sudo

Where>username<Is the name of the user you just created. Now edit the/etc/ssh/sshd_configFile. Find this line:

#PermitRootLogin yes

And change it to:

#PermitRootLogin no

Now restart the SSH service and you are good to go:

/etc/init. D/sshd restart

Windows

Disabling the Administrator account on WindowsIs described on Microsoft Technet. Generally it will be disabled by default, but you should check yourself, to be sure that is the case


Use an Antivirus

For some, but there are people who think they don't need an antivirus (AV) software on their server, this is obvious. So many time I've heard, "Hey, I'm running Linux, I don't need any AV - there is no malware for Linux!". Compared to Windows the number of malicious software is a very little number, Sure. But why would you compare. It's a fact, It exists. And it can infect your machine

Of course AV is not always needed and in some cases it may do more damage than it's worth. For example, if you allow your users to upload anything on your server, youMustUse such software. But if you are in progress of developing something and you test it on your server with AV on, it may be reported to be a virus and you may have a hard time figuring out what happened

Exclusions

To make your system perform better with antivirus software, you should exclude some directories from the scan. This is a tradeoff between complete security and maximum performance. There is a great article onwhat you should do with your AVOn Windows Technet. There is also agood one for LinuxOn Symantec Connect Community


Accessing Your Server

The way you access your server is also important. Here are few tips on how to access your server securely:

Never Connect From Public Hotspots

This is a common mistake. Never use a public wi-fi hotspot to access your server. You don't know who is running it - it may be someone who is just spying on everyone who is connected to the access point. Even if the owner of the hotspot is not such a person (for example in a very popular coffee shop), if it's not secured, someone else may be sniffing on everyone using it (man in the middle attack). Be cautious - if you were accessing your server using SSH before and now it has a different fingerprint (your SSH client should notify you about it) abort the connection and try to find another access point, If you really have to use a public hotspot to access your server (for example your ultra-important application went down). Different fingerprint means someone who is connected to your network intercepted your communication and is trying to trick you into sending him your password

Use Secure Connection Channels

Using FTP to upload files to your server is not a good idea. So if someone can intercept your communication, The data is not encrypted, he could change what you are uploading so instead of some patch to your app you will get malicious software on your machine. Always use SSH for shell access and SCP to transfer files (it's based on SSH). These protocols use strong encryption to avoid such incidents

Use Verified Software

Use software from official sources like your operating system's package repository or trusted software provider. Never download any software you use to connect to your server from suspicious websites - it may be infected and communication between you and your server may be sent to the attacker. Don't try to find precompiled packages for your system - it's safer to compile it yourself or look for an alternative, if your favorite software is provided by the author only as source code, For example

In Conclusion

Hopefully this article has helped you in protecting yourServerFrom attacks and malicious software. In the next part of this article, we'll focus completely on the third layer of security - yourApplicationItself. So stay tuned where I will show you techniques that you can use to protect your application from attacks and intrusions

Continue reading
0
5127
Final product image
What You'll Be Creating

Introduction

Then you will want your audio to sound the best it possibly can on every device it is compatible with, be it a game or any other kind of app, If you're developing a mobile app that has any kind of audio output

Some mobile devices support Dolby Digital Plus, in particular the Kindle Fire range but also a growing number of other Android devices. For example music or voice, Dolby Digital Plus can dramatically improve the audio output of your app by applying filters that can boost certain parts of your audio output. But luckily Dolby have provided an API that makes using this functionality incredibly simple, This may sound like a complicated thing to achieve

In this tutorial, you will learn how you can develop an app using the Marmalade SDK that can take advantage of Dolby Digital Plus using the Dolby Audio API Marmalade extension. If you're only interested in integrating the Dolby Audio API into your Marmalade application, then head to the bottom of this article

1. Overview

The app we'll be creating in this tutorial will provide a simple user interface containing a top row of buttons that can start and stop different kinds of audio, and a bottom row of buttons to set the type of audio filtering that needs to be applied

And the folders and source files that will make up the project, We'll first create a new Marmalade project

Next I'll explain how to implement the user interface by loading an image containing the required button images and drawing different parts of it on the screen. I will also illustrate how to use Marmalade to respond to user touches

And raw sound sample data, compressed audio, such as an MP3 file, Once the user interface is up and running, I'll show you how to make Marmalade play two different types of audio

Finally, I'll integrate the Dolby Audio API into the app and make use of the different audio filter types it provides

I will assume you are developing on a machine running Windows and already have the Marmalade SDK and a version of Microsoft Visual Studio installed, Throughout this tutorial. Marmalade can also be used with Xcode on OS X and you should still find it easy to follow the steps of this tutorial if you are using a Mac for development

2. Setting Up the Marmalade Project

Step 1: Creating the Source Files and Folder Structure

Create a top level folder calledDolbyTestAppTo contain the project files. Within this folder, create another folder calledSourceLet's also create the files we'll be needing in our project. In theSourceFolder, create five empty files calledButton. CppButton. HMain. CppSound. CppAndSound. H

Step 2: Creating the MKB File

Create an empty file calledDolbyTestApp. MkbIn theDolbyTestAppFolder and open it in a code editor. The MKB file is the file used by Marmalade to configure the project. It brings together all your source and data files, and allows you to configure things like the icons used by your app when installed on the different platforms supported by Marmalade. Add the following to theDolbyTestApp. MkbFile

{
    [Source]
    (source)
    button. Cpp
    button. H
    main. Cpp
    sound. Cpp
    sound. H
}Subprojects
{
    iwgeom
    iwgx
}

TheFilesSection of an MKB file is used to list all the source files needed by your project. It also allows you to apply arbitrary groupings to these files and reference files from more than one folder. Groups are defined using square brackets, so the line[Source]Will create a group calledSourceUsing groups allows us to create organizational folders within the Visual Studio solution that we'll generate in the next step

Rounded brackets are used to specify a folder in which Marmalade should look for source files. The line(source)Instructs Marmalade to look in theSourceSubfolder of our main project folder. The five source files for the project are listed after this line

TheSubprojectsSection allows you to reference other source code modules that your project requires. This project will need theIwgeomAndIwgxModules which are standard components provided by the Marmalade SDK

Step 3: Creating a Visual Studio Project

You can now use the MKB file to create a Visual Studio solution that can be used to build and test the app. Double-click the MKB file in Windows File Explorer, which should automatically launch Visual Studio and open the solution

If you take a look at theDolbyTestAppYou will see that a few new files have been created, folder. There's a folder calledBuild_dolbytestapp_vcxxWhere theXxPart of the folder name depends on the version of Visual Studio you're using. This folder is used by Marmalade to contain all files needed as part of the build process, including the Visual Studio solution file

ADataFolder has also been created, such as graphics and audio files, which is where you should place any resources required by the app. Two files have also been automatically created for you in this folder:

  • App. Icf:Such as the maximum amount of RAM the app can use,  a configuration file that allows you to change app settings
  • App. Config. Txt: used to define custom application specific parameters that can then be used in theApp. IcfFile

For this tutorial you can safely ignore these files as no changes will need to be made to it

3. Building the User Interface

Step 1: Implementing the Main Program Loop

Let's start writing the main program loop for our app. In Visual Studio open theSourceDouble-click the, folder in the Solution ExplorerMain. CppFile, and add the following code snippet

#include "IwGx.h"
#include "s3e.h"
#include "button.h"
#include "sound.h"

void Initialise(){
}Void Terminate(){
}Void Update(){
}Void Render(){
}Int main()
{
    Initialise();
    while (. S3eDeviceCheckQuitRequest())
    {
        Update();
        Render();
    }Terminate();
    return 0;
}

This code snippet starts by including two Marmalade header files. TheIwGx. HFile declares the functions and structures that make up Marmalade'sIwGxWhich can be used for rendering both 2D and 3D graphics in the most efficient manner possible on the target device,  API

TheS3e. HSound support, and much more, touch screen input, header file lets you access all the lower level functions that provide direct access to such things as device settings

TheMainFunction is self-explanatory. It starts by calling InitialiseWhich will perform any setup required by the app and ends by callingTerminateWhich will release any resources used by the app

The main while loop starts after invoking InitialiseThe exit condition is little more than a call toS3eDeviceCheckQuitRequestWhen the user has closed the app or the operating system has requested it to shut down for some reason, which is a Marmalade function that checks to see if a request to close the app has been received, for example

The main loop just calls theUpdateAndRenderFunctions continuously. TheUpdateFunction will be used for things like detecting user input while Render is responsible for drawing the user interface

TheInitialiseUpdateRenderAndTerminateFunctions are all empty at the moment, but the app can be built and executed. If you want to give it a try in theMarmalade Windows SimulatorSelect theX86 DebugOption from theSolution ConfigurationsDrop-down menu in the Visual Studio toolbar, pressF7To build the app, andF5To execute it. You should see something similar to the screenshot below

Step 2: Loading an Image

To display the user interface the app is going to need to have some images to render, so I'll now show you how to load a PNG image into memory and get it into a state where it can be rendered to the screen

First, add the following line at the top of theMain. CppBelow the include statements at the top:, file

CIwTexture* gpTexture = NULL;

TheCIwTextureClass is used to represent a bitmapped image. In the above snippet,  I'm declaring a global variable calledGpTextureWhich will be used to store a pointer to the image used in the app's user interface.  The image file we'll be using is namedUi. Png

The image can be loaded into memory and prepared for use by adding the following lines to theInitialiseFunction

// Initialise Marmalade modules
IwGxInit();

// Create a new CIwTexture and use it to load the GUI image file
gpTexture = new CIwTexture;
gpTexture->LoadFromFile("ui.png");
gpTexture->Upload();

The call toIwGxInitPerforms all the necessary initialization steps needed to allow the app to draw to the screen, which includes being able to load image files

TheGpTextureVariable is used to store a pointer to a new instance of theCIwTextureClass. A call to theLoadFromFileMethod with the file name of the image will load the PNG file into memory and convert it into a suitable format for rendering. The image file name is specified relative to the app'sDataSo you'll need to ensure the, folderUi. PngFile is copied to this folder

The call to theUploadReady to be drawn on screen, method will upload the converted image data to the device's video memory

So when the app shuts down it should release any resources it may be using, It's also important that we tidy up after ourselves. Add the following to theTerminateFunction

// Destroy texture instance
delete gpTexture;

// Terminate Marmalade modules
IwGxTerminate();

The above snippet first destroys theCIwTextureRepresenting the, instanceUi. PngWhich will also release any hardware resources and memory used by the image, image. The call toIwGxTerminate releases any resources that were initially allocated by the call toIwGxInit inInitialise

Step 3: Creating a Button Class

The user interface for this app is going to need some clickable buttons, so let's create a new class calledButtonThat will implement this behavior. Open Button. HFile and enter the following code

#ifndef BUTTON_H
#define BUTTON_H

#include "IwGx.h"

class Button
{
public:
    Button(CIwTexture* apTexture, int32 aHeight, int32 aWidth, int32 aX, int32 aY, int32 aUWidth, int32 aU, int32 aVWidth, int32 aV, bool aEnabled);
    ~Button();

    void Render();

private:
    CIwMaterial* mpMaterial;
    CIwSVec2 mTopLeft;
    CIwSVec2 mSize;
    CIwFVec2 mUV;
    CIwFVec2 mUVSize;
    bool mEnabled;
};

#endif

The constructor for this class is used to position and size the button on screen, and also to indicate which region of the source image should be displayed on the button. It also indicates whether this button should be enabled for user input

The destructor will release any resources created by the constructor while theRenderUnsurprisingly, draw the button on the screen, method will

Some more Marmalade classes are introduced for the member variables of theButtonClass. TheCIwMaterialClass is used by Marmalade to combine images with other rendering information, such as color data that might be required when rendering. TheCIwSVec2Class is a two component vector where each component is a 16-bit signed integer. TheCIwFVec2Class is another two component vector with each component being of type Float

OpenButton. CppAnd add the following code snippet to implement the ButtonClass

Bool aEnabled)
{
    mpMaterial = new CIwMaterial();
    mpMaterial->SetTexture(apTexture);

    float lTextureWidth = (float) apTexture->GetWidth();
    float lTextureHeight = (float) apTexture->GetHeight();

    mTopLeft, int32 aV, int32 aVHeight, int32 aU, int32 aHeight, int32 aY, #include "button.h"
#include "s3e.h"

Button::Button(CIwTexture* apTexture, int32 aX, int32 aWidth, int32 aUWidth. X = aX;
    mTopLeft. Y = aY;
    mSize. X = aWidth;
    mSize. Y = aHeight;
    mUV. X = (float) aU / lTextureWidth;
    mUV. Y = (float) aV / lTextureHeight;
    mUVSize. X = (float) aUWidth / lTextureWidth;
    mUVSize. Y = (float) aVHeight / lTextureHeight;

    mEnabled = aEnabled;
}

The constructor for theButtonClass starts by creating a new instance ofCIwMaterialWhich will be used to render the button image. EachButtonInstance has its own CIwMaterial instance as it makes it easier to change the button's color. Once theCIwMaterialThe, instance is createdCIwTextureInstance passed into the constructor is set as its image

TheMTopLeftMember variable is used to store the top left corner of theButtonOn the screen while MSizeStores the width and height. These values are specified in pixels

TheMUVAndMUVSizeMember variables store the top left corner and dimensions of the image region to be rendered. These are specified as a floating point fraction of the source image size, with0), (0Being the top left corner of the image and1), (1Being the bottom right corner

So you need to convert these into fractional values by dividing by the pixel width or height of the source image, The values passed into the constructor are specified as pixel offsets into the texture. It is possible to find the image dimensions by calling theGetWidthAndGetHeightMethods on theCIwTextureClass

The next code snippet shows the class's destructor. As you can see, all it has to do is delete theCIwMaterialInstance that was allocated in the constructor

Button::~Button()
{
    delete mpMaterial;
}

TheRenderMethod will draw theButtonOn screen. It starts by checking theMEnabledMember variable and sets the ambient color of theCIwMaterialSo that theButtonIs drawn at full brightness when enabled and a bit darker when disabled.  A call toIwGxSetMaterialTells Marmalade whichCIwMaterialInstance to draw with and IwGxDrawRectScreenSpaceWill cause theButtonTo be rendered

Void Button::Render()
{
    if (. &mUVSize);, 255);

    IwGxSetMaterial(mpMaterial);
    IwGxDrawRectScreenSpace(&mTopLeft, &mUV, &mSize, 96, mEnabled)
        mpMaterial->SetColAmbient(96, 255);
    else
        mpMaterial->SetColAmbient(255, 255, 96, 255
}

Step 4: Laying Out the User Interface

The user interface for the app is going to automatically adjust to the screen resolution of the device it is running on, but to make things a little simpler we're only going to support landscape orientation. The first step is to force landscape by entering the following into theApp. IcfFile

[S3E]
DispFixRot=LANDSCAPE
MemSize0=12000000

{OS=WINDOWS}WinWidth=1280
WinHeight=800
{}

All settings in the app.icf file have a group associated with them. Square brackets are used to denote a group, so in this case the line [S3E] indicates the settings that follow are part of the S3E group, which is a group reserved by Marmalade for hardware related settings.

The DispFixRot setting will force the screen to always be in landscape orientation. The MemSize0 setting has also been added to increase the amount of RAM the app has available to it. When you add sound support later in this tutorial, the extra RAM will be needed to store the sound sample data.

The WinWidth and WinHeight settings are used to specify the dimensions of the windows used when running in the simulator. The {OS=WINDOWS} line ensures these settings are only used on the Windows simulator. The {}Line disables this restriction so any settings following it become global settings again

You can now start creating the elements of the user interface. Open theMain. CppFile and start by adding the following snippet after the declaration of theGpTextureGlobal variable

BUTTON_FILTER_OFF, BUTTON_FILTER_GAME, BUTTON_AUDIO_OFF, BUTTON_FILTER_MOVIE, BUTTON_COUNT, BUTTON_AUDIO_MUSIC, BUTTON_FILTER_MUSIC, BUTTON_AUDIO_SFX, BUTTON_FILTER_VOICE, enum ButtonIDs
{
    BUTTON_AUDIO_LABEL, BUTTON_FILTER_LABEL, BUTTON_AUDIO_SPEECH
};

Button* gButton[BUTTON_COUNT];

bool gDolbySupported;

TheButtonIDsEnumeration provides a convenient way of naming each of the user interface elements. TheGButtonArray will store pointers to each of theButtonInstances in the user interface and theGDolbySupportedBoolean flag will be used to disable parts of the interface if the target device does not support the Dolby Audio API

To create the requiredButtonInstances, add the following code to the end of theInitialiseFunction

// Check for Dolby Digital Plus support
gDolbySupported = false;

// Create our interface buttons
int32 lSize = IwGxGetScreenWidth() / 5;
int32 lGap = (int32) ((float) lSize * 0. 1f);
lSize = (int32) ((float) lSize * 0. 160, lTopRowY - lLabelHeight - 10, lLabelHeight, 353, 173, lBottomRowX, lTopRowX + (3 * (lSize + lGap)), lSize, 174, lLabelHeight, lTopRowX + (2 * (lSize + lGap)), lBottomRowY, gDolbySupported);
gButton[BUTTON_FILTER_VOICE] = new Button(gpTexture, 347, 42, lBottomRowY, 3, 160, lSize, true);
gButton[BUTTON_AUDIO_SPEECH] = new Button(gpTexture, lSize, lSize, 160, 160, 4, false);
gButton[BUTTON_AUDIO_OFF] = new Button(gpTexture, lTopRowX + (lSize + lGap), lBottomRowX + (lSize + lGap), 175, 160, lLabelWidth, 160, 347, lSize, 240, 160, lSize, 42, lBottomRowY, true);
gButton[BUTTON_AUDIO_MUSIC] = new Button(gpTexture, 160, lBottomRowY, lSize, 240, lSize, lTopRowY, 160, 173, lBottomRowX + (4 * (lSize + lGap)), lLabelWidth, 160, lSize, lTopRowY, 2, false);
gButton[BUTTON_FILTER_OFF] = new Button(gpTexture, gDolbySupported);
gButton[BUTTON_FILTER_GAME] = new Button(gpTexture, 160, lSize, 160, 175, 160, lBottomRowX + (2 * (lSize + lGap)), lSize, 3, 160, 173, 9f);

int32 lRowSize = IwGxGetScreenHeight() / 4;
int32 lTopRowX = (IwGxGetScreenWidth() - (4 * lSize) -
                 (3 * lGap)) / 2;
int32 lTopRowY = lRowSize - (lSize / 2);
int32 lBottomRowX = (IwGxGetScreenWidth() - (5 * lSize) -
                    (4 * lGap)) / 2;
int32 lBottomRowY = (3 * lRowSize) - (lSize / 2);
int32 lLabelWidth = (240 * lSize) / 160;
int32 lLabelHeight = (42 * lSize) / 160;
int32 lLabelX = (IwGxGetScreenWidth() - lLabelWidth) / 2;

gButton[BUTTON_AUDIO_LABEL] = new Button(gpTexture, 160, 2, lLabelX, lTopRowX, true);
gButton[BUTTON_AUDIO_SFX] = new Button(gpTexture, lSize, gDolbySupported);
gButton[BUTTON_FILTER_MOVIE] = new Button(gpTexture, 160, 160, lBottomRowY, lTopRowY, lBottomRowX + (3 * (lSize + lGap)), lTopRowY, 3, lSize, lLabelX, 173, gDolbySupported);, 174, 160, 408, gDolbySupported);
gButton[BUTTON_FILTER_MUSIC] = new Button(gpTexture, lBottomRowY - lLabelHeight - 10, true);
gButton[BUTTON_FILTER_LABEL] = new Button(gpTexture, 3, lSize, lSize, 2, 3, lSize, 2, lSize, lSize

We start by assuming the Dolby Audio API isn't supported by the user's device by setting, In this code blockGDolbySupportedToFalseNext, theIwGxGetScreenWidthAndIwGxGetScreenHeightFunctions are used to infer the dimensions of the screen and suitable sizes and positions for the user interface elements are calculated. A number of, FinallyButtonDefining the user interface, instances are created

You may have noticed that the ButtonInstances for controlling the current filter type use theGDolbySupportedVariable to indicate whether they should be enabled or not. I've cheated a little by using two disabledButtonInstances to draw some labels

But you should always ensure that you tidy up after yourself, You've now created the user interface. Add the following code block at the start of theTerminateFunction to release theButtonInstances when the app shuts down

// Destroy Button instances
for (uint32 i = 0; i < BUTTON_COUNT; i++)
{
    delete gButton[i];
}

But it still won't be rendered, the user interface would be created and destroyed, If you were to run the app at this point. You will need to add the following code snippet to theRenderFunction before anything will be displayed on screen

// Clear the screen to a pale blue
IwGxSetColClear(128, 0);
IwGxClear(IW_GX_COLOUR_BUFFER_F, 255, 224. IW_GX_DEPTH_BUFFER_F);

// Render the UI
for (uint32 i = 0; i < BUTTON_COUNT; i++)
{
    gButton[i]->Render();
}// Finish rendering and display on screen
IwGxFlush();
IwGxSwapBuffers();

The above code snippet first clears the screen to light blue using calls toIwGxSetColClearAndIwGxClearThen, the user interface is drawn by calling theRenderMethod on each of theButtonInstances. Finally, a call toIwGxFlushCauses all render requests to be completed beforeIwGxSwapBuffersMakes the user interface actually appear on screen

If you build and run the app in theMarmalade Windows SimulatorWith the bottom row drawn darker as they are in a disabled state, you should see two rows of buttons


Step 5: Responding to User Input

Let's now make this app a little more interactive by tracking touch input from the user. You'll need to add a new method to the, To startButtonClass, so openButton. HAnd add the following method prototypes

Int32 aY);
bool IsReleased();, int32 aX, void Update(uint32 aTouchState

You should also add the following additional private member variables to theButtonClass

Bool mPressed;
bool mDown;
bool mReleased;

Open, NextButton. Cpp and add the following lines to the end of the class constructor to ensure the new member variables are initialized to sensible values

MDown = false;
mPressed = false;
mReleased = false;

The next code block shows the implementations of theUpdateAndIsReleasedMethods

Void Button::Update(uint32 aTouchState, int32 aX, int32 aY)
{
    if (. MEnabled)
        return;

    // Check if the touch position is within bounds of
    // this button
    aX -= mTopLeft. X;
    aY -= mTopLeft. Y;

    bool lInBounds = (aX >= 0) && (aX < mSize. X) &&
                     (aY >= 0) && (aY < mSize. Y);

    // Clear the released flag
    mReleased = false;

    // Check touch screen state
    if (aTouchState & S3E_POINTER_STATE_PRESSED)
    {
        // User has just touched the screen
        if (lInBounds)
        {
            mPressed = true;
            mDown = true;
        }
    }Check if user
        // is still touching inside it
        if (mPressed)
        {
            mDown = lInBounds;, else if (aTouchState & S3E_POINTER_STATE_DOWN)
    {
        // If button has been pressed
        }
    }We set the release flag to true
        if (mPressed && mDown)
        {
            mReleased = true;, else if (aTouchState & S3E_POINTER_STATE_RELEASED)
    {
        // If user has released screen over a pressed
        // button
        }// Button is no longer pressed or down. MDown = false;
        mPressed = false;
    }
}Bool Button::IsReleased()
{
    return mReleased;
}

TheUpdateThe current touch status and the screen coordinates of the touch, method takes three parameters. You'll learn how to obtain this information shortly. The method first checks to see if theButtonIs disabled and immediately exits if it is. The screen coordinates passed to the method are then checked against the bounds of theButtonTo see if theButtonIs being touched

TheATouchStateParameter of theUpdateMethod is a bit mask comprised of three possible flags:

  • S3E_POINTER_STATE_PRESSED is set when the user has just touched the screen
  • S3E_POINTER_STATE_DOWNIs set while the screen is being touched
  • S3E_POINTER_STATE_RELEASEDIs set when the user lifts its finger from the screen

TheUpdateMethod uses the current value ofATouchStateTo update the internal member variables of the class accordingly

TheIsReleasedMethod is trivial, it returns the current state of theMReleasedVariable

We need to make one final change to theButtonClass. In the RenderMethod, we draw the Button slightly darker while the user is pressing it. This visual feedback benefits the user experience of the application. Change the beginning of theRenderMethod to the following:

If (. 96, 255);
else
    mpMaterial->SetColAmbient(255, 192, 255, 255);
else if (mDown)
    mpMaterial->SetColAmbient(192, 192, 255);, 255, 96, mEnabled)
    mpMaterial->SetColAmbient(96

With theButtonClass updated, you now just have to add some logic to detect touch input from the user. OpenMain. Cpp again and add the following to the currently emptyUpdateFunction:

// Allow device OS time to do its processing
s3eDeviceYield(0);

// Update pointer (actually touch screen. X, ) inputs
s3ePointerUpdate();

// Read current touch screen inputs and use them to update Button states
uint32 lTouchState =
           s3ePointerGetState(S3E_POINTER_BUTTON_SELECT);
int32 x = s3ePointerGetX();
int32 y = s3ePointerGetY();
for (uint32 i = 0; i < BUTTON_COUNT; i++)
{
    gButton[i]->Update(lTouchState, y);
}

The call toS3eDeviceYieldSuch as touch input, incoming calls, etc, is vitally important in a Marmalade app as it allows the device's operating system time to handle any events. TheS3ePointerUpdateFunction takes a snapshot of the current touch screen status

The current state of the first detected touch input is then found by callingS3ePointerGetStateIt returns a value using the bit mask I described earlier.  TheS3ePointerFunctions are also used to detect mouse events on desktop operating systems. The value passed toS3ePointerGetStateIsS3E_POINTER_BUTTON_SELECTDepending on the capabilities of the device the app is running on, which will return the status of the first detected touch event or the left mouse button

S3ePointerGetXAndS3ePointerGetYReturn the screen coordinates of the touch. We then loop through the button instances and call Button::Update on each button, passing in the current touch screen status and touch coordinates

The app is now capable of detecting user input and theButtonInstances will change color when they're pressed

4. Adding Audio Playback

Step 1: Playing Compressed Audio Files

Such as MP3 files, Playing back compressed audio files, is incredibly easy in Marmalade. It only takes a single line of code, In fact. Add the following code block to the end of theUpdateFunction inMain. Cpp

// Check for button presses
if (gButton[BUTTON_AUDIO_MUSIC]->IsReleased())
{
    s3eAudioPlay("black-hole.mp3");
}

Whenever the user presses and releases the music note button on the top row of buttons,  the app will call theS3eAudioPlayWhich will attempt to play the MP3 file called, functionBlack-hole. Mp3This file must exist in the projectData folder, so it can be located at runtime

TheBlack-hole. Mp3File was obtained fromhttp://www.freesfx.co.uk and was composed by Craig Riley (SOCAN)

Step 2: Playing Uncompressed Sound Samples

Playing uncompressed sound samples is also possible in Marmalade. It's more flexible as it allows you to play multiple sounds at a time, whereas most devices will only allow a single compressed audio track to be played back at any time, While it isn't quite as simple as playing a compressed sound file

Marmalade expects sound sample data to be in 16-bit signed PCM format and most audio editing software will allow you to save out files in this format using theWAV file formatMarmalade doesn't support the WAV file format directly, However, so for the purposes of this tutorial I have taken sound files saved in WAV format and removed the header from the file leaving only the sample data. You'd probably want to support WAV files directly, but that is beyond the scope of this tutorial, For your own apps

I've added two sound files to theDataFolder calledFemale-counting. RawAndGun-battle. RawThe original WAV format files were obtained fromhttp://soundbible.com and have been released under the Attribution 3. 0 Creative Commons license

It is necessary to have the sound data in memory, In order to play a sampled sound effect. I have created aSoundClass that will take care of this for us. To implement this class, open upSound. H and add the following code block to it:

#ifndef SOUND_H
#define SOUND_H

#include "s3e.h"

class Sound
{
public:
    Sound(const char* apFileName);
    ~Sound();

    void Play();

private:
    int16* mpSoundData;
    uint32 mSamples;
};

#endif

Open, NextSound. CppAnd insert the following code block:

#include "sound.h"

Sound::Sound(const char* apFileName)
{
    // Attempt to open the sound effect file
    s3eFile* f = s3eFileOpen(apFileName, f);

        // Close the file
        s3eFileClose(f);, S3E_FILESEEK_END);

        // Number of samples is file size divided by the
        // size of an int16
        mSamples = s3eFileTell(f) / sizeof(int16);
        s3eFileSeek(f, sizeof(int16), "rb");
    if (f)
    {
        // Seek to end of file to find its length
        s3eFileSeek(f, mSamples, S3E_FILESEEK_SET);

        // Allocate buffer for sound data
        mpSoundData = new int16[mSamples];

        // Read in sound data
        s3eFileRead(mpSoundData
    }Else
    {
        // File open failed, zero the member variables
        mpSoundData = NULL;
        mSamples = 0;
    }
}Sound::~Sound()
{
    if (mpSoundData)
        delete[] mpSoundData;
}Void Sound::Play()
{
    if (mpSoundData)
    {
        int lChannel = s3eSoundGetFreeChannel();
        s3eSoundChannelPlay(lChannel, mSamples, mpSoundData, 0);
    }
}

The constructor takes the file name of a sound effect and finds the length of the file in bytes. And the file is read into this buffer, big enough to hold the entire sound, An array of 16-bit signed integers is created. The destructor deletes this buffer

ThePlayMethod will actually start the sound sample playing. It does this by first asking Marmalade for a free sound channel with a call toS3eSoundGetFreeChannel The sound is then started on that channel by callingS3eSoundChannelPlayAnd the number of sound samples in the sound,  passing in the channel number, start of the sound buffer. The remaining two parameters indicate whether the sound sample should loop when it reaches the end and the offset into the sample data where subsequent loops should begin playing. By passing in zero for both of these parameters, the entire sound effect will loop continuously

With theSoundReturn to, class implementedMain. CppAnd add some code to load and destroy the sound samples and to start the sounds playing when the user presses a button. Start by adding two new global variables after the declaration of theGpButtonArray

Sound* gpGunBattleSound;
Sound* gpFemaleCountingSound;

Add the following to the end of the, NextInitialiseFunction. This code block will load the two sound files into memory and then set the default sound sample frequency to 44100Hz, which just so happens to be the frequency of both sounds used in the app

44100);, // Load sound effects into memory
gpGunBattleSound = new Sound("gun-battle.raw");
gpFemaleCountingSound = new Sound("female-counting.raw");

// Configure default sample rate for s3eSound
s3eSoundSetInt(S3E_SOUND_DEFAULT_FREQ

We also need to release the sound data on shut down. We do this by adding the following code block to the beginning of the Terminate function to destroy theSoundInstances

// Destroy sound effects
delete gpGunBattleSound;
delete gpFemaleCountingSound;

Finally, add the next code snippet to the end of the UpdateFunction, immediately after the end of the last IfStatement. This will start the sound effects playing in response to the user pressing the correct buttons

Else if (gButton[BUTTON_AUDIO_SFX]->IsReleased())
{
    if (gpGunBattleSound)
        gpGunBattleSound->Play();
}Else if (gButton[BUTTON_AUDIO_SPEECH]->IsReleased())
{
    if (gpFemaleCountingSound)
        gpFemaleCountingSound->Play();
}

Step 3: Stopping Audio Output

Chances are you'll also eventually want to stop it playing, If you want to start a piece of audio playing. The code block below illustrates how to do this in Marmalade by having a button in the user interface stop all currently playing audio. Add the following block to the end of theIf. ElseBlock at the very end of theUpdateFunction inMain. Cpp

Else if (gButton[BUTTON_AUDIO_OFF]->IsReleased())
{
    s3eAudioStop();
    s3eSoundStopAllChannels();
}

The call toS3eAudioStopWill stop playback of any compressed audio track that is playing, while S3eSoundStopAllChannelsWill stop all uncompressed sampled sounds. It is possible to stop sampled sounds on a channel by channel basis, but for the purposes of this app it's fine to stop all channels that are currently active

5. Integrating the Dolby Audio API

Step 1: Downloading the Dolby Audio API Marmalade Extension

It's time to turn our attention to the Dolby Audio API, Now that we have an app that can play some sounds. Adding support for the Dolby Audio API is incredibly simple and can be done in no more than five minutes, As you'll notice

You first need to obtain the Dolby Audio API Marmalade extension by visiting theDolby Developer websiteAfter creating a free developer account, you can download the Marmalade extension from theFrameworkTab

Step 2: Adding the Dolby Audio API to the Project

Extract the Dolby Audio API Marmalade extension archive to a folder on your development machine and find in the extracted Libraries folder for a folder named S3eDolbyAudioCopy this folder and its contents into our project's DolbyTestApp folder, alongside the Source and Data folders

To include the extension in your project, edit the DolbyTestApp. Mkb file and add S3eDolbyAudio to the list of SubprojectsIf you then rebuild the project in Visual Studio, the MKB file will be reprocessed and the Dolby Audio API extension will be added to to the project

Step 3: Initializing the Dolby Audio API

Before you can use the functionality of the Dolby Audio API, you must first check whether the device your app is running on supports Dolby Digital Plus. Edit, To implement the necessary checksMain. CppAnd add the following#include at the top of the file

#include "s3eDolbyAudio.h"

Next, declare a global variable namedGDolbyInitialised after the declaration ofGDolbySupported

Bool gDolbyInitialised;

You can add the following code block to the, To check whether Dolby Digital Plus is supportedInitialiseFunction, after the statement GDolbySupported = false;

If (s3eDolbyAudioAvailable() == S3E_TRUE)
{
    if (s3eDolbyAudioSupported() == S3E_TRUE)
    {
        gDolbySupported = true;
    }S3eDeviceYield(0);
}

The first call toS3eDolbyAudioAvailableChecks whether the Dolby Audio API extension is supported on the target platform. If the extension is available a call is made toS3eDolbyAudioSupportedWhich will returnS3E_TRUEIf the target device supports Dolby Digital Plus. The, If supportedGDolbySupportedFlag is setTrue

The call toS3eDeviceYieldIs to give the device time to perform background processing after doing the Dolby Digital Plus support test. So the, Dolby recommend that you do not initialize Dolby Digital Plus immediately after checking whether it's supportedS3eDeviceYield call will help prevent issues during initialization

At the end of theInitialiseFunction, you can initialize Dolby Digital Plus by calling theS3eDolbyAudioInitializeFunction. Only if this function returnsS3E_TRUEWill theGDolbyInitialisedFlag be setTrueThe code you need to add is as follows:

// Initialise Dolby API
if (gDolbySupported)
{
    if (s3eDolbyAudioInitialize() == S3E_TRUE)
    {
        gDolbyInitialised = true;
    }
}

So add the following to the, You should also shut down the Dolby Audio API when your program terminatesTerminateBefore the call to, functionIwGxTerminate

// Release resources used by Dolby API
if (gDolbySupported)
{
    s3eDolbyAudioRelease();
}

Step 4: Handling Suspending and Resuming

It isn't uncommon for your app to be suspended, either because the user wants to perform a different task or an event such as an incoming call has occurred, Since mobile phones and tablets are used for a plethora of tasks. Under these conditions the Dolby Audio API should be suspended so that it isn't active whilst your app is paused or running as a background task

Marmalade allows us to set up some callback functions that will be triggered whenever the app loses or regains focus. Add the following code to the, To implement theseInitialiseFunction immediately after the check for Dolby Digital Plus support

AppSuspended, AppResumed, NULL);
s3eDeviceRegister(S3E_DEVICE_BACKGROUND, NULL);, // Initialise Pause/Resume callbacks
s3eDeviceRegister(S3E_DEVICE_PAUSE, AppSuspended, NULL);
s3eDeviceRegister(S3E_DEVICE_UNPAUSE, NULL);
s3eDeviceRegister(S3E_DEVICE_FOREGROUND, AppResumed

You should also remove these callback functions at shut down, so add the following lines to theTerminateFunction immediately after theDelete gpTextureLine

// Disable Pause/Resume callbacks
s3eDeviceUnRegister(S3E_DEVICE_PAUSE, AppResumed);, AppResumed);
s3eDeviceUnRegister(S3E_DEVICE_FOREGROUND, AppSuspended);
s3eDeviceUnRegister(S3E_DEVICE_UNPAUSE, AppSuspended);
s3eDeviceUnRegister(S3E_DEVICE_BACKGROUND

Now you just need to implement theAppSuspendedAndAppResumedCallback functions. Add this code after the declaration of the global variables at the top ofMain. Cpp

Void* apUserData)
{
    if (gDolbyInitialised)
        s3eDolbyAudioSuspendSession();
    return 0;, int32 AppSuspended(void* apSystemData
}Int32 AppResumed(void* apSystemData, void* apUserData)
{
    if (gDolbyInitialised)
        s3eDolbyAudioRestartSession();
    return 0;
}

The, When the app is suspended or goes into background processingAppSuspendedCallback will be triggered, which callsS3eDolbyAudioSuspendSessionIf theGDolbyInitialisedFlag isTrue , When the app regains focusAppResumedWhich invokes , will be calledS3eDolbyAudioRestartSessionIf the Dolby Audio API has been initialized

Step 5: Using the Dolby Audio API Filters

The final step to integrating the Dolby Audio API is to actually make use of the different audio filters it provides.  which suit different types of audio output, There are four predefined filters availableMovieMusicVoiceAndGame

Once the Dolby Audio API is active, passS3E_TRUE toS3eDolbyAudioSetEnabledTo ensure filtering support is switched on followed by a call toS3eDolbyAudioSetProfileIf you want to stop filtering you can do this with a call toS3eDolbyAudioSetEnabledPassing inS3E_FALSE

Add the following code block to the end of theUpdateFunction to enable the bottom row of buttons to switch between the different filter types

If (gButton[BUTTON_FILTER_OFF]->IsReleased())
{
    if (gDolbyInitialised)
    {
        s3eDolbyAudioSetEnabled(S3E_FALSE);
    }
}Else if (gButton[BUTTON_FILTER_MUSIC]->IsReleased())
{
    if (gDolbyInitialised)
    {
        s3eDolbyAudioSetEnabled(S3E_TRUE);
        s3eDolbyAudioSetProfile(MUSIC);
    }
}Else if (gButton[BUTTON_FILTER_MOVIE]->IsReleased())
{
    if (gDolbyInitialised)
    {
        s3eDolbyAudioSetEnabled(S3E_TRUE);
        s3eDolbyAudioSetProfile(MOVIE);
    }
}Else if (gButton[BUTTON_FILTER_GAME]->IsReleased())
{
    if (gDolbyInitialised)
    {
        s3eDolbyAudioSetEnabled(S3E_TRUE);
        s3eDolbyAudioSetProfile(GAME);
    }
}Else if (gButton[BUTTON_FILTER_VOICE]->IsReleased())
{
    if (gDolbyInitialised)
    {
        s3eDolbyAudioSetEnabled(S3E_TRUE);
        s3eDolbyAudioSetProfile(VOICE);
    }
}

6. Making a Device Build

Step 1: Including the Resource Files

Let's round off by getting the app running on a device. The first step is to ensure that the final deployment package contains all the necessary resource files. EditDolbyTestApp. MkbAnd append the following code snippet to the end of the file

Assets
{
    [default]
    (data)
    black-hole. Mp3
    female-counting. Raw
    gun-battle. Raw
    ui. Png
}Deployments
{
    name="DolbyTestApp"
    caption="Dolby Test App"

    assets="default"
}

TheAssetsSection of an MKB file is used to list the resource files that need to be shipped with the executable in order for the app to run. The format is similar to theFilesUsing square brackets to make groupings of files and rounded brackets to indicate folder names where files can be found, section

The Deployments section lets you configure the final installation package. The Name parameter lets us specify the file name that will be used for the package file and the Caption parameter is used to declare the text that will appear beneath the app icon when it is installed on a device. TheAssetsParameter references one of the groups defined in theAssetsSo it is possible to switch between different asset sets should you need to, if you want to create a full and lite version of your app, section, for example

Step 2: Making the Installation Package

You must first compile the app source code for the type of processor used by the target device, To create an installation package for the device of your choosing. In most cases, so you should select the, this will be an ARM chipGCC ARM ReleaseOption from theSolutions ConfigurationsDrop-down menu at the top of the Visual Studio toolbar

PressF7Followed by , to build the appF5To launch theMarmalade Deployment Tool

TheMarmalade Deployment Tool shows a wizard to create the installation packages. If you want to create an Android build, then you must first choose the build type, which will also run on Kindle Fire devices, For exampleARM GCC Release

After clicking theNext Stage >Button, you will be asked to choose which project configuration you wish to deploy. Check the Default configuration,  and click the , which is the only configuration of our projectNext Stage >Button once more to see a list of platforms supported by your version of Marmalade. Tick the box next toAndroidAnd click the Next Stage > button again

You can now choose what actions to take when creating the installation package. The drop-down menu lets you choose to just create the package, install, create it and install it on a device connected via USB, which means you'll need to manually install it on a device, or create, and run the app on a connected device. You'll need the, For the latter two options to workAndroid SDKBecause these options make use of the, installed on your development machineADB which is part of the Android SDK, tool

But you can read more about this topic on the, A discussion of how to set up an Android device for development use is beyond the scope of this tutorialAndroid Developer website

Conclusion

As you can see, using the Dolby Audio API in a Marmalade app is a very simple process. Most of this tutorial was concerned with setting up the user interface or playing sounds rather than integrating the Dolby Audio API

Then you really should consider adding support for Dolby Digital Plus to give your users the best possible audio experience, If you've written a game or any other kind of app in Marmalade that has rich audio output

Continue reading
0

Testimonial

Thank you so much! We are very happy with our new website. It is easy to use and all of our customers tell us, they love it.

Contact Us

  • 13245 Atlantic Blvd. #4352
    Jacksonville, FL 32225
  • 904-240-5823