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

We will continue to focus on our business logic, In this tutorial. We will evaluate ifRunnerFunctions. PhpTo which class, belongs to a class and if so. We will think about concerns and where methods belong. We will learn a little bit more about the concept of mocking, Finally. What are you waiting for, So. Read on

RunnerFunctions - From Procedural to Object Oriented

Nicely organized in classes, Even though we have most of our code in object oriented form, some functions are just simply sitting in a file. We need to take some in order to give the functionsRunnerFunctions. PhpIn a more object oriented aspect

$maxAnswerId = MAX_ANSWER_ID) {
	return rand($minAnswerId, $maxAnswerId), const WRONG_ANSWER_ID = 7;
const MIN_ANSWER_ID = 0;
const MAX_ANSWER_ID = 9;

function isCurrentAnswerCorrect($minAnswerId = MIN_ANSWER_ID. = WRONG_ANSWER_ID;
}5) + 1;
		$aGame->roll($dice);, function run() {
	$display = new CLIDisplay();
	$aGame = new Game($display);

	do {
		$dice = rand(0
	}While (. IsCurrentAnswerCorrect()));, didSomebodyWin($aGame
}Function didSomebodyWin($aGame, $isCurrentAnswerCorrect) {
	if ($isCurrentAnswerCorrect) {
		return. $aGame->wasCorrectlyAnswered();
	}Else {
		return. $aGame->wrongAnswer();

My first instinct is to just wrap them in a class. But it is something that makes us start changing things, This is nothing genius. Let's see if the idea can actually work

$maxAnswerId = MAX_ANSWER_ID) {
		return rand($minAnswerId, $maxAnswerId), const WRONG_ANSWER_ID = 7;
const MIN_ANSWER_ID = 0;
const MAX_ANSWER_ID = 9;

class RunnerFunctions {

	function isCurrentAnswerCorrect($minAnswerId = MIN_ANSWER_ID. = WRONG_ANSWER_ID;
	}Function run() {
		//. //
	}Function didSomebodyWin($aGame, $isCurrentAnswerCorrect) {
		//. //

We need to modify our tests and our, If we do thatGameRunner. PhpTo use the new class. Renaming it will be easy when needed, We called the class something generic for the time being. We don't even know if this class will exist on its own or will be assimilated intoGameSo don't worry about naming just yet

Private function generateOutput($seed) {
	(new RunnerFunctions())->run();
	$output = ob_get_contents();
	return $output;

In ourGoldenMasterTest. PhpWe must modify the way we run our code, file. The function isGenerateOutput()And its third line needs to be modified to create a new object and callRun()On it. But this fails

PHP Fatal error:  Call to undefined function didSomebodyWin() in

We now need to modify our new class further

Do {
	$dice = rand(0, 5) + 1;
}While (. $this->didSomebodyWin($aGame, $this->isCurrentAnswerCorrect()));

We only needed to change the condition of theWhileStatement in theRun()Method. The new code callsDidSomebodyWin()AndIsCurrentAnswerCorrect()From the current class, by prepending$this->To them

But it brakes the runner tests, This makes the golden master pass

PHP Fatal error:  Call to undefined function isCurrentAnswerCorrect() in /. /RunnerFunctionsTest. Php on line 25

The problem is inAssertAnswersAreCorrectFor()But easily fixable by creating a runner object first

Private function assertAnswersAreCorrectFor($correctAnserIDs) {
	$runner = new RunnerFunctions();
	foreach ($correctAnserIDs as $id) {
		$this->assertTrue($runner->isCurrentAnswerCorrect($id, $id));

This same issue needs to be addressed in three other functions as well

WRONG_ANSWER_ID));, function testItCanFindWrongAnswer() {
	$runner = new RunnerFunctions();
}Function testItCanTellIfThereIsNoWinnerWhenACorrectAnswerIsProvided() {
	$runner = new RunnerFunctions();
	$this->assertTrue($runner->didSomebodyWin($this->aFakeGame(), $this->aCorrectAnswer()));
}Function testItCanTellIfThereIsNoWinnerWhenAWrongAnswerIsProvided() {
	$runner = new RunnerFunctions();
	$this->assertFalse($runner->didSomebodyWin($this->aFakeGame(), $this->aWrongAnswer()));

It introduces a bit of code duplication, While this makes the code pass. We can extract the runner creation into a, As we are now with all tests on greenSetUp()Method

Private $runner;

function setUp() {
	$this->runner = new Runner();
}Function testItCanFindCorrectAnswer() {
}WRONG_ANSWER_ID));, function testItCanFindWrongAnswer() {
}$this->aCorrectAnswer()));, function testItCanTellIfThereIsNoWinnerWhenACorrectAnswerIsProvided() {
}Function testItCanTellIfThereIsNoWinnerWhenAWrongAnswerIsProvided() {
	$this->assertFalse($this->runner->didSomebodyWin($this->aFakeGame(), $this->aWrongAnswer()));
}$id));, private function assertAnswersAreCorrectFor($correctAnserIDs) {
	foreach ($correctAnserIDs as $id) {

Nice. All these new creations and refactorings got me thinking. We named our variableRunnerMaybe our class could be called the same. Let's refactor it. It should be easy

If you didn't check "Search for text occurrences" in the box above, because the refactoring will rename the file also, don't forget to change your includes manually

Now we have a file calledGameRunner. PhpAnother one namedRunner. PhpAnd a third one namedGame. PhpI don't know about you, but this seems extremely confusing to me. I would have no idea which one does what, If I was to see these three files for the first time in my life. We need to get rid of at least one of them

The reason we created theRunnerFunctions. PhpWas to build up a way to include all the methods and files for testing, file in the early stages of our refactoring. We needed access to everything, but not run everything unless in a prepared environment in our golden master. Just not run our code from, We can still do the same thingGameRunner. PhpBefore we continue, We need to update the includes and create a class inside

Require_once __DIR__. '/Display. Php';
require_once __DIR__. '/Runner. Php';
(new Runner())->run();

That will do it. We need to includeDisplay. PhpExplicitly, so whenRunnerTries to create a newCLIDisplayIt will know what to implement

Analyzing Concerns

I believe that one of the most important characteristics of object oriented programming is defining concerns. "is this class doing what its name says?", "Is this method of concern for this object?", "Should my object care about that specific value?", I always ask myself questions like

These types of questions have a great power in clarifying both business domain and software architecture, Surprisingly. We are asking and answering these types of questions in a group at Syneto. He or she just stands up, asks for two minutes of attention from the team in order to find our opinion on a subject, Many times when a programmer has a dilemma. Those who are familiar with the code architecture will answer from a software point of view, while others, more familiar with the business domain may shed light on some essential insights about commercial aspects

Let's try to think about concerns in our case. We can continue to focus on theRunnerClass. Than, It is hugely more probable to eliminate or transform this classGame

Should a runner care about how, FirstIsCurrentAnswerCorrect()Working. Should a runner have any knowledge about questions and answers

It really seems like this method would be better off inGameI strongly believe that aGameAbout trivia should care if an answer is correct or not. I truly believe aGameMust be concerned about providing the result of the answer for the current question

It's time to act. We will do aMove methodRefactoring. I will just show you the end result, As we've seen this all before from my previous tutorials

Require_once __DIR__. '/CLIDisplay. Php';
include_once __DIR__. '/Game. Php';

class Runner {

	function run() {
		//. //
	}$isCurrentAnswerCorrect) {
		//, function didSomebodyWin($aGame. //

But the constant defining the answer's limits also, It is essential to note that not only the method went away

But what aboutDidSomebodyWin()Should a runner decide when someone has won. If we look at the method's body, we can see a problem highlighting like a flashlight in the dark

$isCurrentAnswerCorrect) {
	if ($isCurrentAnswerCorrect) {
		return, function didSomebodyWin($aGame. $aGame->wasCorrectlyAnswered();
	}Else {
		return. $aGame->wrongAnswer();

It does it on a, Whatever this method doesGameObject only. It verifies the current answer returned by game. Then it returns whatever a game object returns in itsWasCorrectlyAnswered()OrWrongAnswer()Methods. This method effectively does nothing on its own. All it cares about isGameThis is a classic example of a code smell calledFeature EnvyA class does something that another class should do. Time to move it

Class RunnerFunctionsTest extends PHPUnit_Framework_TestCase {

	private $runner;

	function setUp() {
		$this->runner = new Runner();


As usual, we moved the tests first. TDD. Anyone

So this file can go now, This leaves us with no more tests to run. Deleting is my favorite part of programming

We get a nice error, And when we run our tests

Fatal error: Call to undefined method Game::didSomebodyWin()

It's now time to change the code as well. Copying and pasting the method intoGameWill magically make all the tests pass. Both the old ones and the ones moved toGameTestBut while this puts the method in the right place, it has two problems: the runner also needs to be changed and we send in a fakeGameObject which we do not need to do anymore since it is part ofGame

5) + 1;
	$aGame->roll($dice);, do {
	$dice = rand(0
}While (. $aGame->didSomebodyWin($aGame, $this->isCurrentAnswerCorrect()));

Fixing the runner is very easy. We just change$this->didSomebodyWin(. )Into$aGame->didSomebodyWin(. )After our next step, We will need to come back here and change it again. The test refactoring

Function testItCanTellIfThereIsNoWinnerWhenACorrectAnswerIsProvided() {
	$aGame = \Mockery::mock('Game[wasCorrectlyAnswered]');

It's time for some mocking. We will use, Instead of using our fake class, defined at the end of our testsMockeryIt allows us to easily overwrite a method onGameExpect it to be called and return the value we want. We could to this by making our fake class extend, Of courseGameAnd overwrite the method ourselves. But why do a job for which a tool exists

Function testItCanTellIfThereIsNoWinnerWhenAWrongAnswerIsProvided() {
	$aGame = \Mockery::mock('Game[wrongAnswer]');

We can get rid of the fake game class and any methods that initialized it, After our second method is rewritten. Problems solved

Final Thoughts

Even though we managed to think about only theRunnerWe made great progress today. We identified methods and variables that belong to another class, We learned about responsibilities. We thought on a higher level and we evolved toward a better solution. There is a strong belief that there are ways to write code well and never commit a change unless it made the code at least a little bit cleaner, In the Syneto team. This is a technique that in time, can lead to a much nicer codebase, with less dependencies, more tests and eventually less bugs

Thank you for your time

Continue reading

Most people have the wrong idea about automation. They often think of a futuristic fantasy of robots that automatically do everything for you. That would be the ultimate in automation. More practically, automation is any assistance in performing related actions. Therefore, anytime you can get the computer to help in an activity is automation

Entering in numbers in to a spreadsheet and performing calculations with the numbers is a type of automation, For example. It's automation, Each time the spell checker corrects a misspelled word in the text. Even the notification of an email arriving is a type of automation

Taking advantage of automation is the mindset of looking for ways to have your computer help your activities. Unfortunately,  do not have the mindset to take advantage of automation, Most people. You think about how to do an activity and just do it. A mindset for automation has the thought of looking for anything performed more than two times as a candidate for automation

In order to make use of automation, you have to understand the different types of automation and how they work. With that knowledge, you will start looking for ways to put that knowledge in to action

Types of Automation

All automation comes in one of three types:Process automationTrigger automationAndHybrid automationEach of these have their own sub-types as well. By understanding these types and the applications used for these types of automation, you better know how to create an automation for your needs

Process Automation

Process automationIs the transforming one or more items in to a different item by a predetermined process. Taking a picture and transforming it in to a different file type with a set number of bit planes is a process automation, Therefore.  

The changing of a markdown text file to a HTML file is also a process automation. This would also encompass the moving of files from one place to another. You have, When you perform the process automation repetitivelyBatch automation

Trigger Automation

Trigger automationHappens when running a process upon an event. An event is anything that the computer has no direct control over, but can respond to it.  

In the real world, an alarm clock is the classic example of a trigger automation. All automations that follow aWhen… then…Construction is a trigger automation

I came up with six trigger automation subtypes:Time triggersState triggersText triggersHotkey triggersKeyword triggersAndExternal triggersI will describe each trigger subtype with it’sWhen… then…Description

Time Trigger

ATime triggerAutomation is any activation of a program on a timed interval. It can be as simple as a message about an upcoming meeting or a routine that launchesSkypeTo make the meeting possible.  

Polling a directory for new files and performing an action upon them is a time trigger automation.  

WhenA certain time interval or date happensThenPerform an action

State Trigger

State trigger automation is the process of over viewing a system and performing an action based on the systems change of state.  

A thermostat is a state trigger automation, In home automation. The thermostat triggers the turning off or on of the air conditioner, When the house temperature reaches a certain point.  

WhenThe computer is in a certain stateThenPerform an action

Text Trigger

Text triggerAutomation is a specialized form ofState triggerA text trigger automation only watches over the keyboard input to determine the sequence of the text typed. An appropriate action and/or text replacement gets performed, When a certain sequence gets detected.  

This is different fromKeyword triggersIn that this type of automation does not make use of a special input area. Any program that receives text can receiveText triggerAutomation.  

WhenThe user types a certain key sequence anywhereThenChange the text and/or perform an action

Hotkey Trigger

Hotkey triggerAutomation is another specialized form ofState triggerA hotkey trigger automation only watches for a certain combination of keys pressed together. It will perform a special action that gets assigned to that combination.  

All text editors make use of this type of automation.  WhenCertain keys get pressed togetherThenPerform a certain action

Keyword Trigger

AKeyword triggerAutomation is aText triggerAutomation in a specialized text input area. These can take extra input to perform the automation as well. The terminal is a keyword trigger automation, With this broad of a definition.  

WhenA certain text gets keyed in to a specialized text inputThenPerform an action with or without extra input from the user

External Trigger

AnExteral triggerAutomation is the triggering a process based on a stimulus from outside the program or computer. But responding to a stimulus, It is not monitoring. This is analogous to a clicker on a slide projector. The presenter clicks the clicker to get the projector to change slides.  

TheExternal triggerBut can be a service, does not have to be a device. Push notifications is an application ofExternal triggerAutomation.  

WhenAn event from outside the program or computer happensThenPerform a predetermined action

Hybrid Automation

Hybrid automationIs the combination of any of the aforementioned automation types put togetherHybrid automationIs generally the most powerful type of automation, but it often is the hardest to put together and maintain.  

The easiest form of hybrid automation is aSequential automation: one automation triggers another automation that is non-related. This differs fromBatch automationBy invoking a different type of automation

Programs for Automation

I’ll give you some programs to think about each type of automation and how you can put it to work for you, Now that I’ve explained the types of automation. This isn’t an exhaustive list of programs to use for each type of automation, but a short list to get you started

Process and Batch Automation

Two great program for doing generic process automation areDropZoneAndAlfredThese two programs allow you to process items and create customizations that fit a particular need. These programs also allow for simple batch processing of actions

Alfred Workflow for Project Management
Alfred Workflow for Project Management

Alfed WorklfowsExist for many task automations. ThePackalWebsite lists over 220 workflows. TheProject ManagementLaunching servers, workflow automates the creation of new web projects, and anything else I add to it. It’s my workhorse of project automation.  

You can see how the base of it created inAlfred Workflows for Advanced Users

Dropzone Compressing Images
Dropzone Compressing Images

DropzoneComes with several pre-built actions and the ability to add more. In the tutorialWriting Destinations for DropzoneYou see how to create an action to take any image and compress it to a smaller bit plane and to a different type. Once written for doing one image, it is automatically setup to run batch processing as well

TextSoap Cleaner Construction
TextSoap Cleaner Construction

TextSoapIs a process automation for text only. It allows you to change text in many ways: different types of cases, Markdown to HTML or Richtext, and custom text cleaners that’s built with an easy to use flowchart construction method.  

The tutorialHow to Effortlessly Create Markdown With TextSoapShows how to create text processing automations

Time Triggers

You have to have programs that know about time and can react to the time, To make use of time automation. A simple calendar program likeFantasticalIs great, but it does not automate an action. But does not help in the work you need to do, It gives great reminders

Clockwise Setting Up Action
Clockwise Setting Up Action

Programs like, ThereforeClockwiseAndAlfred CronMake for true automations. These programs allow you to run a script at a certain time point.  

ClockwiseWould be the program of choice for programming novices. It has many built-in actions along with user definable scripts.  Alfred CronIs for advanced users.  

The tutorial,  Use a Mac to Monitor Website Uptime or Other Regular TasksShows how to automate actions on time using these applications

State Triggers

There is only one trueState TriggerProgram for the Mac that I know about:ControlPlane

ControlPlaneWorks by monitoring many factors in your Mac to determine the current state. Scripts can execute to automate the Mac, Once the state changes. The tutorialTake Control With ControlPlaneShows how to use this program to automatically turn on and off file sharing based on location

A limited form ofState TriggeringHappens with programs likeLiveReloadAndHazelThese programs are known asFile State TriggeringAutomations. They watch the state of certain files. When their state changes (ie. Changed by a save file action), then they perform a pre-defined action


LiveReloadRecompiles web centric resources. Therefore, if you useCompassOrSASSSet live reload to monitor your directories, or many other web centric pre-compilers in your project. It automatically recompiles them and reloads the change in to your browser, Anytime you change a file in those directories


WhileLiveReloadDoes a specific type of file processingHazelIs more generic. It polls predetermines files for a large number of possible changes and performs an action.  

You can configureHazelTo function likeLiveReloadAnd more, though HazelIs not as responsive asLiveReloadFor this type of functionality because of it’s polling nature

Text Triggers

When I needText TriggersI reach toTextExpanderTo fill that area. Combined withPopClipAnd theTextExpander ExtensionI can create text expanders quickly

TextExpander Selecting Text
TextExpander: Selecting Text

You can select the text you want to expand and select theTextExpander ExtensionInPopClip

TextExpander Assigning Expanding Key
TextExpander: Assigning Expanding Key

Set the key trigger. I use;qAs my default work expander that I do not keep. I can type, to repeat that sequence of text, Now;qAnd it expands. When done, delete it or set it to a unique expansion text for future use.  

You can be sure that it will not get triggered by normal typing, By using a semi-colon before the letter sequence. This saves a lot of typing

Hotkey Triggers

For Hotkey TriggersKeyboard MaestroIs my main application withAlfredDoing the rest

Coupled withShortCatA program that allows you to select interface features solely from the keyboard, you can make some interesting automations

Keyboard Maestro and ShortCat Automating Web Forms
Keyboard Maestro and ShortCat Automating Web Forms

For example, one of my jobs is uploading video courses to Wistia and getting them formatted properly. I use aKeyboard MaestroHotkey action to create a new section in the course.  

In the aboveKeyboard MaestroA, dialogCmd-Up ArrowMoves to the top of the web page inChromeAShift-Command-SpaceCallsShortCatTo look for a field calledProject ActionThat opens a menu.  

The script callsShortCatAgain to select a menu item in that menu. What normally takes me several mouse moves is a single keyboard shortcut. That is automation at it’s finest

Keyword Triggers

To create a keyword Trigger, I mostly useAlfredBy creating a workflow for the actions needed. In anAlfredI can use any programing language I want to create the actions, workflow.  

The group of tutorials teaching the use of Alfred will help you learn to create keyword triggered actions: Alfred forBeginnersIntermediatesAdvancedAndAlfred Debugging

LaunchBar 5 AppleScript Actions
LaunchBar 5 AppleScript Actions

LaunchBarLikewise is useful in creating actions triggered by a keyword. In version 5, they had to beAppleScriptScripts.  

AnyAppleScriptScript placed in the~/Library/Application Support/LaunchBar/Actions/Directory is accessible inLaunchBarAs a keyword action

LaunchBar 6 Packaged Actions
LaunchBar 6 Packaged Actions

The latest version 6 ofLaunchBarAdds the ability to use any programming language to create scripts and a nice way to package all the needed information together

External Triggers

BothKeyboard MaestroAndAlfredAllow for programs other than itself to call their functions with anExternal Trigger 

Keyboard MaestroGoes one further and supports an internal Web Server to receive triggers from anywhere on the Internet. You can therefore have a computer somewhere on the Internet send a trigger event toKeyboard MaestroOn your computer

Alfreds External Trigger
Alfred’s External Trigger

Alfred’sExternal TriggerIs limited to a program that can run anAppleScriptScript to call it. When you define anExternal TriggerAlfred gives you the AppleScript code to use to call it

Hybrid Automation

SinceHybrid AutomationThere really is not a single application designed for this purpose, is the combining of multiple automation techniques together.  

As you can see from my list of applicationsAlfredIs in many of the categories. Since it is easy forAlfredCreating a, to call itselfHybrid AutomationIs very doable


I have explained computer automation and how to perform it on a Mac, In this tutorial.  

It’s up to you to transform your workflow to take advantage of automation. Just keep thinking: I can automate anything done more than twice

Continue reading
Final product image
What You'll Be Creating


I really enjoy portraiture. It is very satisfying and tells a lot about the person in the photo, When it's done well. Frizzies, there is always a little element that is a constant problem for me: fly-away hair, or whatever you call them, However. They're the strands of hair that stick out from the person's head and make your photo look a little messy. Especially with corporate or fashion photographs, they're practically unacceptable and must go

I'll be showing you three techniques that will give you options when tackling those pesky follicles while keeping the final result natural-looking. It's a balancing act of taste vs need while keeping it realistic, As with any retouching. Then you'll end up with "helmet hair" which often looks fake, If you go too far

Retouching an image is supposed to be done well and subtle enough that the viewer doesn't notice it. But the rest comes from good technique and application, A lot of that comes from producing the shot properly in the first place. So, having your subject well-groomed or using a hair stylist can be really helpful in reducing the amount of time and effort needed to fix hair's errant ways. For the rest, use these three techniques

Technique #1: Clone Stamp Tool

Clone StampIs the Captain Obvious choice for removing heretical hair in Adobe Photoshop. Simply sample the clean area and then brush over the hair and make it go away. However, you'll notice that it has short-comings, if you've used this tool before

Pixel-by-pixel, Its main strength is also its main weakness: it copies exactly what you sampled. This can be a problem with textured backgrounds or variations in color or luminosity. With evenly-lit and evenly-colored backgrounds, the, HoweverClone StampIs awesome

Nasty fly-away hair
The Clone Stamp Tool couldn't handle the gradient, re-sampled repeatedly and closely, Even though I used a very small brush size, and used the Lighten blend mode

You can further refine your cloning and reduce problematic color/luminosity variations by using differentBlend ModesFor the brush. I use only three different modes:

  • Normal
  • Darken
  • Lighten

TheNormalMode works most of the time, but sometimes it's too exacting and can be a problem with backgrounds that have a slight texture. Using the other two modes can make my changes literally hair-thin.  

Blend modes

I use theDarkenBlend mode to retouch lighter hair that's against a darker background. I use theLightenBlend mode to retouch darker hair against a lighter background. The effect stops once the hair reaches the same luminosity and color value as the sampled area. It will leave the areas that already match untouched, so your corrections are only a couple pixels wide even if your brush size is many times larger

Technique #2: Healing Brush Tool

TheHealing BrushIs a more refined version of theClone StampTool. It copies the color, luminosity, and texture from the sampled area over to the target area. It then applies some math and very seamlessly blends the two into something that looks natural

TheHealing BrushPimples, sensor dust, is great for removing blemishes, etc, unwanted facial or body hair. It works better than the cloning technique mainly because it isn't an exact copy, but smoothly blends the target and sample areas with the target's surroundings

Use this tool for backgrounds that are a little more complex or textured -- wherever theClone StampIs failing. You can also use it to clean up mistakes theClone StampHas made while preserving the texture. I use it for hair that crosses the face or is on clothing so that I can be rid of it without losing the complexities of the skin or fabric

You can utilize the, AgainBlend ModesTo further refine your retouching

The blending prowess of the, UnfortunatelyHealing BrushIs also a shortcoming. Such as the edge of someone's head, It doesn't do well when your target area is too close a hard line. You'll get a blurred bleed and it looks messed up. In this case, theClone StampTool may be better suited, adjust the brush's hardness to match the transition

Blurred bleed produced by the Healing Brush
You can see what happens when the Healing Brush can do when it gets close to a high-contrast edge. This can happen even if your brush is tiny

Brush Settings

So, but we'll go over some common settings I use that get the job done, now you know two tools that zap away errant hair and when to use them. I've figured that these tend to produce the best and controllable results, Through experiment and experience

Too, but this will work with a mouse, I use a Wacom tablet for maximum control and flexibility. If you don't own a Wacom and you're doing retouching, then buy a pen tablet. They start at about $80 (USD) and last a long time. Mine is six years old

Clone Stamp

I usually keep the default shape settings, and use it at 100%, a circleOpacityBut rarely go over 80%, I vary the brush's hardness. 50%, In fact, I use this brush at 0%, 20%, and 80% increments as I've found it covers most of my needs. Of course there are times that I'll use a different hardness setting, but that is case-by-case. I can vary that further with pen pressure, And with the pen tablet

I utilize different, Like I mentioned earlierBlend ModesWhen I need to. Appropriately matching these different settings to your situation will result very good cloning and a faster workflow

Healing Brush

A lot of people would tell you to use this brush with a soft edge. I'm going to tell you to do the opposite. Keep it at 100%HardnessAll the time. Additionally, change your brush's shape (Roundness) to a narrow ellipse between 20 and 30%. I also angle it and change the direction, depending on my needs

Adjusting brush parameters
You can change the angle to adapt to each situation

What these settings do is help theHealing BrushWork better by forcing it to re-sample more often and more randomly than a soft-edged circle. Since theHealing BrushAutomatically applies blending, you really don't need a soft brush. The results have been very natural as well as a greatly reduced risk of that edge blurring I mentioned earlier

Finally, keep your brush size only slightly larger than the area you wish to correct, especially with fly-away hair close to the edge of someone's head or if the background changes color or luminosity too greatly

Technique #3: Surface Blur

It does incorporate the others for maximum efficacy, While this technique is mainly independent of the other two. It is a really quick way to remove nearly all that fly-away hair with a single filter effect with some basic masking. It is faster than going over each hair with either the, Aside from the processing bottleneckClone StampOrHealing Brush

UnlikeGaussian BlurOr the other blursSurface BlurDoesn't blend the edges beyond it's threshold settingSurface BlurConsiders something an "edge" when there is a significant change in color and/or contrast. Things like skin, and other fine details will be smoothed, but not the edge of someone's face -- or the main mass of hair, clothing, So

Gaussian Blur and Surface Blur compared side-by-side
Gaussian Blur, left, just blends everything together. Right, Surface Blur, keeps edges defined

Surface BlurIs a great way to clean up a hair edge when you have a gradient background -- where theClone StampWould struggle. It will do a nice job maintaining gradual tonal changes while keeping hard edges well-defined. Give it a go when you have an image with a graduated background

Let's get into the steps for usingSurface BlurTo clean up hair in your images

Back to the begining again
Here is our sample head. Lots of little stray hair and the Surface Blur technique will do a lot of the work for us. (ISO 200, 1/160sec, f/8, flash comp +1. 3)

Step 1: Create a New Layer

Drag the layer onto the "Create New Layer" icon (Cmd+JOrCtrl+J) so that you don't affect any previous retouching you've done. You can convert this new layer into aSmart Object(Layer > Smart Objects > Convert to Smart Object) to be able to change your settings without having to reapply the filter from scratch. Converting to aSmart ObjectIs optional

Step 2: Apply the Surface Blur

Go toFilter > Blur > Surface BlurIn order apply it. You'll see a preview of the effect at its current settings

TheSurface BlurFilter has two slidersRadiusAndThresholdTheRadiusDetermines the amount/strength of blurring. TheThresholdDetermines the tolerances of what the filter considers to be an "edge." Going too low with theRadiusWill give you a halo and going too high with theThresholdWill make you lose your edges. But the main body of hair and hard edges remain quite sharp, You'll need to adjust the sliders so that the fly-away hair disappears due to the blurring. This will take some experimenting and will vary from image to image. However, I've found that aRadiusOf 40 pixels andThresholdOf 20 pixels gives me great results

Adjust Radius and Threshold controls for the Surface Blur tool
A lot of the stray hair is gone while the main body of hair is intact, As you can see

Once you've gotten the settings pretty close, apply it and evaluate the results. A lot of the isolated hair should be gone or mostly gone

Before and After Surface Blur
The hairline has been cleaned-up significantly, After applying Surface Blur. The stragglers can easily be handled with the Clone Stamp Tool. (230% zoom)

Step 3: Clone Stamp Clean-up

There are times when theSurface BlurGets the job done, but often you'll need to tackle the few that got away. With a soft-edge brushClone StampThose escapees by sampling very close to the target area to avoid noticeable color variations. I keep my brush no higher than 50% hardness

Clean up with Clone Stamp after the Surface Blur filter
Sampling very close to my target area, I got rid whatever the initial Surface Blur missed. I made sure to try to keep it natural-looking, However. (230% zoom)

Try not to make the hairline too clean because then it will look unnatural. You can do a second round of Surface Blur at lower settings if it could use a little more general refinement

Step 4: Create a Layer Mask

Now it's time apply the effect only to the outer hairline. Create aLayer MaskOn your layer with theSurface BlurBy clicking the "Create Layer Mask" icon. Invert the color of the mask from white (visible) to black (invisible) withCmd+I(Mac) orCtrl+I(PC). This will hide the effect

Create Layer Mask
Create a Layer Mask and then invert (Cmd+I or Ctrl+I) it to hide the effect

With a hard-edged brush (about 80%) reveal the effect by painting on the mask with white, Now. Limit the revealing by only brushing over the hair that need to go away. You don't need to be very precise because theSurface BlurShould maintain the edging of the main body of hair

Paint on layer mask to reaveal effect
This is what the mask should look like. (100% zoom)

Step 5: Add Noise

Surface BlurUsually removes all the noise (grain) in an image. This lack of texture can ruin the effect by being too smooth. We'll need to add noise in a dosage that matches the rest of the image

Add noise to match retouched area to rest of image
I zoomed in to 330% to show in more detail the differences between that retouched and un-retouched areas. This is difference is visible at 100% and will be more obvious with high-ISO photographs or under-exposed images that have been brightened

Make sure you're working the image of theSurface BlurLayer and not the mask by clicking on the thumbnail of the layer. Go toFilter > Noise > Add Noise

Select image not mask
Make sure the layer's image thumbnailNotThe layer mask, is highlighted. Otherwise, you'll be adding noise to the layer mask

In theAdd NoiseDialogue boxTurn onTheGaussianAndMonochromeSettings. Adjust the slider until the noise pattern and density closely matches the rest of the image. While not entirely necessary, this small detail does an excellent job hiding the retouching you've done

Turn on Gaussian and Monochrome settings
For this image, I applied 3% Noise. It's not perfect, but is the closest match. At 330% zoom it's really good and when we zoom-out to 100% you won't notice it


Lots of errant strands of hair before retouching
Before retouching
Final image nice clear hair without fly-aways
After retouching

When you have a great portrait, sometimes fly-away hair can really be a pain. While cloning and healing are great, they do have limitations. Using them in conjunction with theSurface BlurTechnique can not only improve your retouching results, but also cut-down on the time and tediousness of either technique alone

You'll be able to evaluate an image and quickly decide which of these techniques will be most effective in removing fly-away hair, With practice

Continue reading

Nowadays, you’ll have a hard time finding a professional developer who doesn’t use a version control system (VCS) such as Git.

But, there are still a few among us who choose not to use a VCS due to preconceived notions they might have about version control.

Here are some myths and excuses that dissuade developers from integrating Git — and any version control system in general — into their workflow.

Myth 1: I don’t need Git because I back up my files

Creating regular backups of your work is definitely a good habit. Consider keeping this habit even when using Git.

But Git provides you a lot more benefits compared to just a system of backing up your files.

Without a VCS, you’ll run into a several of issues.

How do you name your backups? If you’re a very organized person, you might be able to stick to an actually comprehendible naming scheme like acme-inc-redesign_2013-11-12_v23.html. However, any deviance from the file-naming convention quickly leads to confusion and, quite possibly, issues with your code.

Let a system like Git worry about the minutia so that you can focus on what you do best: Writing code.

How much of your work are you saving? Only the changed files or the complete project? In the case of the former, it will be tough to see a full picture of a version/variant of your project at any given time. In the case of the latter, where you are backing up the entire codebase at regular intervals, you’ll have huge amounts of redundant files lying around on your hard drive, and more files mean more complications.

The most important issue that can be solved with Git is probably this one:

How do you know what’s different in these backups? Very few people actually take the time to carefully document each and every change they make. On the other hand, Git acknowledges that there is only one project. Everything else — all the past versions and variants — are neatly tucked away in the back-end of the version control system, ready for you whenever you need it. And when you do need it, you can request any version at any time and you’ll have a snapshot of the complete project right at hand.

In addition, you can determine with great precision what has changed in each file. You can tell which lines have been added, which lines have been removed, and which ones have been modified — which means that bug-tracing, emergency rollbacks to stable versions of the project and partial-version rollbacks are much easier processes.

Myth 2: Git is too complicated. It’s not worth the hassle.

People often overestimate how deeply they need to dive into Git to get its main benefits.

It’s true that you can spend a whole lot of time trying to wrap your head around all the fanciest, edge-case Git commands — Git is indeed an extremely powerful and flexible system.

But, it’s also true that you can work productively and reap Git’s major perks with just a handful of commands.

Yes, learning a new skill means more additional work — no one can spare you from that — but the benefits you’ll gain when you start using Git vastly outweighs the time and effort required to learn it.

Learning Git will improve your projects’ quality, as well as your efficiency and productivity as a developer. Also, you will be able to collaborate with other developers in a more systematic and reliable way, delivering even more development-productivity improvements to you and your team.

Myth 3: Git is only for development teams

Distributed version control systems like Git or Mercurial allow you to work completely on your local computer. Should you have projects where you don’t collaborate with anyone else, it’s perfectly valid to perform all tasks on your machine. Git provides as much benefit to the solo developer as it does to dev teams.

You don’t need a remote server or code-hosting service to use Git and to reap its usefulness.

But, it’s worth pointing out that using a remote code-hosting service like GitHub makes sense even as a solo developer, so that you can have external backups of your code in case your computer breaks down or gets lost, or to sync your projects safely across multiple computers (perhaps you have a work laptop and a personal computer at home that you use to develop code with). However, this isn’t necessarily something you need to do; it’s only an optional advantage.

The benefits that Git brings you remain the same, no matter if you’re working in a team or on your own.

Myth 4: The command-line interface is too complicated

You don’t need to be a command-line interface (CLI) expert to use Git. In fact, a handful of commands is all most developers will ever need.

You can learn Git’s important commands in less than an afternoon: We created a guide called Command Line 101 that you can read to learn about the CLI as it pertains to Git — it’s part of our free online book called Learn Version Control with Git: A step-by-step course for the complete beginner.

But let’s just say a handful of basic commands is still too much contact with the CLI for you. Or maybe you made a strange, unbreakable blood pact with a friend never to use the command-line interface ever again, or, for some reason, you simply cannot use a CLI. You can still use Git through an application that has a graphical user interface (GUI). If you’re on Windows, I recommend you take a look at Tortoise Git. On Mac OS, you should give Tower — an app that my company, fournova, has developed — a look-see.

Even for users that are comfortable with the command line, a GUI could still improve productivity by making complex Git tasks easier.

Myth 5: I’m afraid I’ll break something

It should be the other way around: You should be afraid to break things if you don’t use a version control system because it’s hard to retrace your steps and your code-base changes without one.

Version control is our safety net. When things catastrophically break down, we can easily roll back to a previous version that’s stable.

Using Git, you will be able to:

  • undo your local changes (partially or completely)
  • restore any historic version in case something goes wrong
  • revert the effect of any change you made in the past

And I would also like to point out what is in my opinion Git’s most important feature: branches.

Branches provide us with a secure ecosystem for trying out new features, completely separated from other parts of our development project. This encourages us to experiment with new code and to see and test the effects of any code changes while giving us the confidence that we won’t be affecting anything outside of the current branch.

Myth 6: Git is all hype. It’s just a popular trend that will later fade away.

First, Git is definitely not the one and only version control system out there. There are many other great VCS options to consider, each one with its own unique merits.

But it’s not simply by chance that major projects such as jQuery, Rails and the Linux Kernel, just to name a few, rely on Git for version control and code-collaboration.

For coding projects, Git is currently one of the best systems out there. Here are several reasons why Git is a great choice.

Feature Set

Of course, Git’s feature set and philosophy are its biggest value propositions to its users: A great branching model, offline capability, and its "staging area" concept are just some of the prime features that help with the productivity, creativity and efficiency of developers.

Popularity and Staying Power

Being popular and widely available is important for any system. Popularity means there’s a community out there ready to help you get started with the system.

And when you find yourself coding collaboratively, there’s a greater chance your teammates will already know how to use Git.

In addition, being a popular VCS also makes Git attractive for third parties to develop and provide supporting tools and services (e.g. GitHub) that could further enhance your experience with Git.

Popularity also ensures that the Git open source project won’t disappear any time soon — which is an important factor for developers thinking about committing to an open source project for the long-haul.

Official Git website home page (2014).Official Git website home page (2014)

Availability of Quality Educational Materials

It has never been easier to start learning Git. Today, there are tons of documentation, tutorials, videos and how-tos available about the VCS.

Here are a few resources to help you get started with Git.

Why Aren’t You Using Git Yet?

Now over to you: What’s holding you back from using version control with Git? Let us know in the comments!

Related Content

About the Author

Tobias Günther is CEO and founder of fournova. In 2010, he set out to make Git easier to use: Together with his team, he develops the Git desktop client, Tower for Mac.

The post 6 Myths Preventing Developers from Using Git appeared first on Six Revisions.

Continue reading
Final product image
What You'll Be Creating

It's summertime—the time to hit the beach or take a sail. What better time to decorate with a nautical pattern that'll repeat perfectly

Using Adobe Illustrator, you will learn to create marine life wallpaper in a vintage style, In this tutorial. And learn to make the wallpaper seamless, You will use the Pencil Tool to draw different elements. You can follow these steps precisely to make the nautical pattern pictured above, or you can use the steps this tutorials shows to make a pattern with any objects you'd like that repeats perfectly

1. Creating the Marine Life elements

Step 1

PressControl-NButton to create a new document at size600 pxIn the width and height. Select thePencil Tool (N)And on theStrokeSelect, panelRound CapThen adjust thePencil Tool (N)Options:Double-clickOn it on theToolsPanel (Window > Tools) and in the new dialogue window, makeTolerances Fidelity 3 pixelsAndSmoothness 40%CheckFill New Pencil StrokesAnd then pressOkay

Let's draw a seagull as in the image below. You need to hold the, To close the pathAltButton as you finish the path. For the feather decoration on the wing, make the pencil stroke slightly thicker and for the legs, very thick

bird drawing

Step 2

Select the wing and legs, and expand them (Object > Expand). Also you need to expant the beak

bird wings

Step 3

Now remove the strokes and add the fill colors as in the image below

add fill colors

Step 4

Let's draw another element—the anchor. Using thePencil Tool (N)Draw two circles. While keeping them selected, on thePathfinderPress, panelExcludeButton. Then draw bottom part. Now, draw the left arrow. Don't forget to hold theAltButton when as you finish the path. Make sure that the left part of the anchor (arrow) is selected andRight-clickYour mouse. SelectTransform > ReflectCheckVerticalAxis of reflection andAngle 90 degreesThen pressOkayShift the right arrow to the right. Delete the stroke and make the fill color orange (, Select the whole anchorR=214 G=84 B=59). Keep the whole anchor selected,  and on thePathfinderPanel press the UniteButton.  

make anchor

Step 5

Now, let’s draw the lifesaver buoy. Draw two circles again and press theExcludeButton on thePathfinderPanel. Make the fill colorR=232 G=229 B=209Then make very thick stroke on theStrokePanel (stroke colorR=178 G=31 B=41) and draw stripes using thePencil Tool (N)As in the image below. When you are finished, select red stripes and expand them (Object > Expand)

Make one more copy of light gray circle (, NowControl-C) and send it to the front (Control-X, Control-F). You now have two copies of light gray circles. Keep the upper copy selected and while holding theShiftSelect the red stripes, key. Then press theCropButton on thePathfinderPanel


Step 6

Let’s draw the helm—the steering wheel. Using thePencil Tool (N)Draw the helm with thick strokes. Be sure to select theRound CapButton on theStrokePanel. Select the whole thing and expand it (, When you are finishedObject > Expand). Set the fill color to R=188 G=166 B=109


Step 7

We now have all the elements we need to create the seamless wallpaper. As you can see in the image below, I added one more anchor with the same fill color as a body of the seagull. You first need to select the new anchor, then take the, To easily use the same fill colorEyedropper Tool (I)And click on the body of seagull

all elements

2. Creating the Background

Step 1

Let’s draw a large square by using theRectangle Tool (M)Click on your artboard and in the new dialogue window, make the following rectangle options:Width600 pxAndHeight 600 pxSet the fill color toR=61 G=66 B=73Send this square to the back (Control-X, Control-B). Helm, two anchors, Randomly scatter all elements (seagull, lifesaver buoy) all over the square

artboard with scattered elements

3. Creating a Seamless Pattern

Step 1

Pick theSelection Tool (V)And select all the marine life elements, without the background. Group them together (Right-click > Group). Press theEnterKey andMoveWindow should pop up. Enter inHorizontal Position 600 pxVertical Position 0 pxDistance 600 pxAnd set the Angle b 0 degreesPress the, NowCopyButton

copied elements

Step 2

Select all the elements inside the artboard again and press theEnterKey. In theMoveWindow, makeHorizontal Position -600 pxVertical Position 0 pxDistance 600 pxAndAngle 0 degreesPress theCopyButton

copy again

Step 3

Select all the elements inside the artboard once again and press theEnterKey. In theMoveMake, windowHorizontal Position 0 pxVertical Position 600 pxDistance 600 pxAnd theAngle 90 degreeS. Press theCopyButton

final copy

Step 4

Select all the elements inside the artboard for the last time and press theEnterKey. In theMoveWindow, makeHorizontal Position 0 pxVertical Position -600 pxDistance 600 pxAnd theAngle -90 degreesPress theCopyButton

completed scattershot

Step 5

You need to ungroup everything, Now. Select all the elements (Control-A) and ungroup them (Right-click > Ungroup). You need to delete all the marine life elements that do not cross the background

For example the seagull on the top of the wallpaper, Important point—if you want to move, you need to select the corresponding seagull on the bottom of the wallpaper at the same time. Or you need to move the helm from the left side of the wallpaper, you need to move the same corresponding helm from the right side of the wallpaper

Your result should look like the image below:

4. Cropping the wallpaper

Step 1

Group all the marine life elements without the background. You can select everything (, For thisControl-A) and while holding down theShiftKey, then uncheck the background. Anchors, helms and lifesaver buoys, Now that you have selected just seagulls, group them together (Right-click > Group). Make another copy of the background (Control-F, Control-C) and send it to the front (Control-F, Control-X). Keeping the new copy of the background selected, hold down theShiftKey and select the grouped marine life elements. Go toPathfinderPanel and press theCropButton

 and go to, And last but not least: keep the cropped wallpaper selectedObject > Path > Clean upThenOkayYou need this to delete the paths without the fill and stroke

all paths

Step 2

You should now have something like the image below:

finished artboard

Step 3

You did it. Now your summer vintage marine life wallpaper is done. You can drag the whole pattern to theSwatchesPanel and use it for printing, set as a background, fill the shapes that you created in AI, and more

completed pattern


And it looks beautiful, Congrats, you got your seamless pattern created. Go find a unique way to put it to use, Now, or make another seamless pattern using other elements you've made

Continue reading


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