text:
package seedu.cmdo.logic.parser;

import static seedu.cmdo.commons.core.Messages.MESSAGE_BLANK_DETAIL_WARNING;
import static seedu.cmdo.commons.core.Messages.MESSAGE_ENCAPSULATE_DETAIL_WARNING;
import static seedu.cmdo.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.cmdo.commons.core.Messages.MESSAGE_INVALID_PRIORITY;
import static seedu.cmdo.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.joestelmach.natty.DateGroup;
import com.joestelmach.natty.ParseLocation;
import com.joestelmach.natty.Parser;

import seedu.cmdo.commons.core.Messages;
import seedu.cmdo.commons.exceptions.IllegalValueException;
import seedu.cmdo.commons.util.StringUtil;
import seedu.cmdo.logic.commands.AddCommand;
import seedu.cmdo.logic.commands.BlockCommand;
import seedu.cmdo.logic.commands.ClearCommand;
import seedu.cmdo.logic.commands.Command;
import seedu.cmdo.logic.commands.DeleteCommand;
import seedu.cmdo.logic.commands.DoneCommand;
import seedu.cmdo.logic.commands.EditCommand;
import seedu.cmdo.logic.commands.ExitCommand;
import seedu.cmdo.logic.commands.FindCommand;
import seedu.cmdo.logic.commands.HelpCommand;
import seedu.cmdo.logic.commands.IncorrectCommand;
import seedu.cmdo.logic.commands.ListCommand;
import seedu.cmdo.logic.commands.RedoCommand;
import seedu.cmdo.logic.commands.SelectCommand;
import seedu.cmdo.logic.commands.StorageCommand;
import seedu.cmdo.logic.commands.UndoCommand;
import seedu.cmdo.logic.commands.UpDownCommand;
import seedu.cmdo.model.task.Priority;

/**
 * Parses user input.
 */
public class MainParser {

    /**
     * Used for initial separation of command word and args.
     */
    private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?<commandWord>\\S+)(?<arguments>.*)");

    private static final Pattern LIST_COMMAND_FORMAT = Pattern.compile("(?<commandWord>\\S+(?:\\s+\\S+)*)(?<arguments>.*)");

    private static final Pattern TASK_INDEX_ARGS_FORMAT = Pattern.compile("(?<targetIndex>.+)");

    private static final Pattern TASK_LOOSE_INDEX_ARGS_FORMAT = Pattern.compile("(?<targetIndex>[^ ]+) (.*)");

    private static final Pattern KEYWORDS_ARGS_FORMAT =
            Pattern.compile("(?<keywords>\\S+(?:\\s+\\S+)*)"); // one or more keywords separated by whitespace

	public static final LocalDate NO_DATE_DEFAULT = LocalDate.MAX;	// All floating tasks are giving this date.
	public static final LocalTime NO_TIME_DEFAULT = LocalTime.MAX;	// All timeless tasks are given this time.
	public static final LocalDateTime NO_DATETIME_DEFAULT = LocalDateTime.of(LocalDate.MAX, LocalTime.MAX);
	public static final String EMPTY_STRING = "";

	private static LocalDateTime dt = NO_DATETIME_DEFAULT;
	private static LocalDateTime dtStart = NO_DATETIME_DEFAULT;
	private static LocalDateTime dtEnd = NO_DATETIME_DEFAULT;
	private static ArrayList<LocalDateTime> datesAndTimes;
	private static String args;
	private static String detailToAdd;
	private static Integer dateTimeType;
	private static String[] splittedArgs;
	private static Boolean floatingRequestInEdit = false;
	private static Boolean priorityRequestInEdit = false;
	private static Boolean onlyOneDateOrTimeRequestInEdit = false;
	private static Integer targetIndex;

	// Singleton
	private static MainParser mainParser;
	private static final Parser parser = new Parser();

    /**
     * Private constructor
     */
	private MainParser() {
    	init();
    }

    public static MainParser getInstance() {
    	if (mainParser == null) {
    		mainParser = new MainParser();
    	} return mainParser;
    }

    //@@author A0139661Y
    /**
     * Initialize main parser.
     */
    private void init() {
    	datesAndTimes = new ArrayList<LocalDateTime>();
    }

    /**
     * Parses user input into command for execution.
     *
     * @param userInput full user input string
     * @return the command based on the user input
     */
    public Command parseCommand(String userInput) {
    	reset();
    	String[] splitedInput = userInput.split("\\s+");
    	String commandWord, arguments;
    	if(splitedInput.length == 2 &&
    			((splitedInput[1].equals("done")) || (splitedInput[1].equals("all")) || splitedInput[1].equals("block"))) {
    		Matcher matcher = LIST_COMMAND_FORMAT.matcher(userInput.trim());
            if (!matcher.matches()) {
                return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
            }
            commandWord = matcher.group("commandWord");
            arguments = matcher.group("arguments");
    	}
    	else{
    		Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
            if (!matcher.matches()) {
                return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
            }
            commandWord = matcher.group("commandWord");
            arguments = matcher.group("arguments");

    	}
    	args = getCleanString(arguments);
        args = convertToTo(args);
        switch (commandWord) {

        case AddCommand.COMMAND_WORD:
            return prepareAdd();

        case BlockCommand.COMMAND_WORD:
            return prepareBlock();

        case SelectCommand.COMMAND_WORD:
            return prepareSelect();

        case StorageCommand.COMMAND_WORD:
        	return prepareStorage();

        case DeleteCommand.COMMAND_WORD:
            return prepareDelete();

        case DoneCommand.COMMAND_WORD:
            return prepareDone();

        case UndoCommand.COMMAND_WORD:
            return new UndoCommand();

        case RedoCommand.COMMAND_WORD:
            return new RedoCommand();

        case ClearCommand.COMMAND_WORD:
            return new ClearCommand();

        case EditCommand.COMMAND_WORD:
        	return prepareEdit();

        case FindCommand.COMMAND_WORD:
            return prepareFind();

        case ListCommand.COMMAND_WORD_DONE:
        case ListCommand.COMMAND_WORD_SHORT_DONE:
            return prepareList("--done");
        case ListCommand.COMMAND_WORD_BLOCK:
        case ListCommand.COMMAND_WORD_SHORT_BLOCK:
        	return prepareList("--block");
        case ListCommand.COMMAND_WORD:
        case ListCommand.COMMAND_WORD_ALL:
        case ListCommand.COMMAND_WORD_SHORT_ALL:
        	return prepareList(args);

        case UpDownCommand.UP:
        case UpDownCommand.UP_ALT:
        	return new UpDownCommand(UpDownCommand.UP);
        case UpDownCommand.DOWN:
        case UpDownCommand.DOWN_ALT:
        	return new UpDownCommand(UpDownCommand.DOWN);
        case UpDownCommand.TOP:
        case UpDownCommand.TOP_ALT:
        	return new UpDownCommand(UpDownCommand.TOP);
        case UpDownCommand.BOTTOM:
        case UpDownCommand.BOTTOM_ALT:
        	return new UpDownCommand(UpDownCommand.BOTTOM);

        case ExitCommand.COMMAND_WORD:
            return new ExitCommand();

        case HelpCommand.COMMAND_WORD:
            return new HelpCommand();

        default:
            return new IncorrectCommand(MESSAGE_UNKNOWN_COMMAND);
        }
    }

    /** PREPARATION METHODS **/
    //@@author A0139661Y
    private Command prepareAdd(){
    	datesAndTimes.clear();
    	try {
        	process();
    		if (dateTimeType <= 1) {
    			return new AddCommand(
    					detailToAdd,
    					dt.toLocalDate(),
    					dt.toLocalTime(),
    					extractPriority(),
    					getTagsFromArgs());
    		} else {
    			return new AddCommand(
    					detailToAdd,
    					dtStart.toLocalDate(),
    					dtStart.toLocalTime(),
    					dtEnd.toLocalDate(),
    					dtEnd.toLocalTime(),
    					extractPriority(),
    					getTagsFromArgs());
    		}
    	} catch (IllegalValueException ive) {
    		return new IncorrectCommand(ive.getMessage());
    	}
    }

    //@@author A0141128R
    private Command prepareBlock(){
    	try {
    		process();
    		overrideDueByDateAndTimeForBlock();
    		return new BlockCommand(
    			detailToAdd,
    			dtStart.toLocalDate(),
    			dtStart.toLocalTime(),
    			dtEnd.toLocalDate(),
    			dtEnd.toLocalTime(),
    			"",
    			getTagsFromArgs());
    	} catch (IllegalValueException ive) {
    		return new IncorrectCommand(ive.getMessage());
    	}
    }

     //@@author A0141128R
     private Command prepareDelete() {
         if (!isIndexInCommandPresent()) {
             return new IncorrectCommand(
                     String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
         }
         return new DeleteCommand(targetIndex);
     }

     //@@author A0141128R
     private Command prepareDone() {
     	if (!isIndexInCommandPresent()) {
             return new IncorrectCommand(
                     String.format(MESSAGE_INVALID_COMMAND_FORMAT, DoneCommand.MESSAGE_USAGE));
         }
         return new DoneCommand(targetIndex);
     }

    //@@author A0141128R
    private Command prepareEdit(){
    	try {
    		if (!isLooseIndexInCommandPresent()) {
    			return new IncorrectCommand(
    	                String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE));
    		}
        args = args.replaceFirst("[0-9]+\\s", "");
        extractDetailForEdit();
    	splittedArgs = getCleanString(args).split(" ");
        // Parse date and time
        extractDueByDateAndTime();
        saveDueByDateAndTime();
        checkSpecialRequestInEdit();
    	//need to change constructor of edit
		if (dateTimeType <= 1) {
			return new EditCommand(
					priorityRequestInEdit,
					floatingRequestInEdit,
					onlyOneDateOrTimeRequestInEdit,
					targetIndex,
					detailToAdd,
					dt.toLocalDate(),
					dt.toLocalTime(),
					extractPriority(),
					getTagsFromArgs());
		}
		else{
			//only use this constructor when time range is keyed in
			assert(dateTimeType!=0);
			return new EditCommand(
					priorityRequestInEdit,
					targetIndex,
					detailToAdd,
					dtStart.toLocalDate(),
					dtStart.toLocalTime(),
					dtEnd.toLocalDate(),
					dtEnd.toLocalTime(),
					extractPriority(),
					getTagsFromArgs());
    		}
    	} catch (IllegalValueException ive) {
    		return new IncorrectCommand(ive.getMessage());
    	}
    }

    //@@author A0141128R
    private Command prepareFind() {
        boolean taskStatus = false; // we assume the user is searching for undone tasks
    	final Matcher matcher = KEYWORDS_ARGS_FORMAT.matcher(args.trim());
        if (!matcher.matches()) {
            return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
                    FindCommand.MESSAGE_USAGE));
        }

        // keywords delimited by whitespace
        final String[] keywords = matcher.group("keywords").split("\\s+");
        final Set<String> keywordSet = new HashSet<>(Arrays.asList(keywords));
        if (keywordSet.contains("--done")) {
        	taskStatus = true;
        	keywordSet.remove("--done");
        }
        return new FindCommand(keywordSet, taskStatus);
    }

    private Command prepareSelect() {
    	if(!isIndexInCommandPresent()) {
            return new IncorrectCommand(
                    String.format(MESSAGE_INVALID_COMMAND_FORMAT, SelectCommand.MESSAGE_USAGE));
        }
        return new SelectCommand(targetIndex);
    }

    //@@author A0141006B
    private Command prepareStorage() {
    	if (args.equals("")) {
    		return new StorageCommand("data/cmdo.xml");
    	}
    	if (args.lastIndexOf("/cmdo.xml") == -1) {
    		args = new StringBuilder(args + "/cmdo.xml").toString();
    	}
    	return new StorageCommand(args);
    }

    //@@author A0139661Y
    /** Passes in index 0, 1 or 2 to the List Command based on what the user wants.
     * 0: not done (all)
     * 1: done tasks
     * 2: blocked tasks
     */
    private Command prepareList(String args) {
        int type = 0; // we assume the user is searching for undone tasks
        if (args.contains("--done")) {
        	type = 1;
        } else if (args.contains("--block")) {
        	type = 2;
        }
        return new ListCommand(type);
    }

//  ============== HELPER METHODS
    //@@author A0139661Y
    /**
     * Processes parameters detail, dbt, dbd, priority.
     *
     * @throws IllegalValueException if any are invalid.
     */
    private void process() throws IllegalValueException {
    	extractDetail();			// Saves to detailToAdd
    	splitArgsAndRemoveTags();	// For arg splitting and to prevent time parser from reading tags.
    	extractDueByDateAndTime(); 	// Saves to datesAndTimes
    	checkPriorityValidity(); 	// Throws exception if priority entered wrongly
    	saveDueByDateAndTime(); 	// Saves to dt family.
    	reset();         			// Clear dates and times
	}

    //@@author A0141006B
    private void splitArgsAndRemoveTags() {
    	splittedArgs = getCleanString(args).split(" ");
    	for (int i=0; i<splittedArgs.length; i++) {
    		if (splittedArgs[i].startsWith("-")) {
    			args = args.replace(splittedArgs[i], "");
    		}
    	}
    }

    //@@author A0139661Y
    /**
     * Extracts the detail embedded in user input ' '.
     *
     * @throws IllegalValueException if only one ' found, or if detail is blank.
     */
    private void extractDetail() throws IllegalValueException {
    	checkValidDetailInput();
    	// Split into '  ...  '
    	String[] details = args.split("^ '(.+)'$");
    	// Details only, get rid of anything after the last '
    	String output = new StringBuilder(details[0]).replace(details[0].lastIndexOf("'")+1,
    													details[0].length(),
    													"").toString();
    	// Details only, get rid of anything before the first '
    	output = new StringBuilder(output).replace(0, output.indexOf("'"), "").toString();
    	// Take out the detail.
    	args = args.replace(output, "");
    	// Get rid of the first '
    	output = output.substring(output.indexOf("'")+1, output.lastIndexOf("'"));
    	// Save to instance
    	detailToAdd = output;
    }

    //@@author A0139661Y
    /**
     * Extracts the detail embedded in user input ' ' for edit purposes.
     * ie details are optional, and if they are input, should not be empty.
     *
     * @throws IllegalValueException if detail is blank.
     */
    private void extractDetailForEdit() throws IllegalValueException {
    	if (!checkValidDetailInputForEdit()) {
    		detailToAdd = "";
    		return;
    	}
    	extractDetail();
    }

    //@@author A0139661Y
    /**
     * Extracts the priority out of the args.
     * If / precedes neither high, medium or low, it will throw an error
     * Otherwise, it is taken to have default no priority.
     *
     * @param splittedArgs an array of split user input
     * @return priority level string.
     */
    private String extractPriority() throws IllegalValueException {
    	List<String> rawArgs = Arrays.asList(splittedArgs);
    	for (String rawArg : rawArgs) {
    		if (rawArg.toLowerCase().startsWith("/")) {
    			switch(rawArg.replace("/", "")) {
    			case Priority.HIGH:
    				return Priority.HIGH;
    			case Priority.MEDIUM:
    				return Priority.MEDIUM;
    			case Priority.LOW:
    				return Priority.LOW;
    			default:
    				throw new IllegalValueException(MESSAGE_INVALID_PRIORITY);
    			}
    		}
    	}
    	return "";
    }

    //@@author A0139661Y
    /**
     * Takes out the date and time of the natural language input
     */
    public void extractDueByDateAndTime() {
    	List<DateGroup> groups = parser.parse(args);
    	String cleanArgs = args;

    	try {
    		// This retrieves either the start date/time, or the only date/time.
    		for (int i=0; i<groups.size(); i++) {
	    		DateGroup group = groups.get(i);
	    		List<Date> dateList = group.getDates(); 	// Extract date
	    		Map<String, List<ParseLocation>> parseMap = group.getParseLocations();
	    		if ((!parseMap.containsKey("explicit_time") && parseMap.containsKey("relative_date")) ||
	    				(!parseMap.containsKey("explicit_time") && parseMap.containsKey("formal_date"))) {
	    			for (Date date : dateList) {
	    				LocalDateTime temp = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
	    				datesAndTimes.add(LocalDateTime.of(temp.toLocalDate(), LocalTime.MAX));
	    			}
	    		} else {
	    			for (Date date : dateList) {
	    				datesAndTimes.add(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()));
	    			}
	    		}
	    		for (ParseLocation parsedWord : parseMap.get("parse")) {
	    			cleanArgs = cleanArgs.substring(0, parsedWord.getStart() - 1) + cleanArgs.substring(parsedWord.getEnd() -1);
	    		}
    		}
    		// Sort dates and times according to whichever is earlier
    		Collections.sort(datesAndTimes);
    		args = cleanArgs;	// Return a cleaned up string
    	} catch (IndexOutOfBoundsException e) {} // No date/time found. Do nothing
    }

    //@@author A0139661Y
    /**
     * Checks if the detail input is valid, as in, it requires the use of encapsulating ' ',
     * and must not be blank. This is used in conjunction with {@link #extractDetail()}.
     *
     * @throws IllegalValueException if only one ' found, or if detail is blank.
     */
	private void checkValidDetailInput() throws IllegalValueException {
    	// Check if only one ' used
    	if (args.lastIndexOf("'") == args.indexOf("'"))
    		throw new IllegalValueException(MESSAGE_ENCAPSULATE_DETAIL_WARNING);
    	// Check if detail is empty.
    	if (args.lastIndexOf("'") == args.indexOf("'")+1)
    		throw new IllegalValueException(MESSAGE_BLANK_DETAIL_WARNING);
	}

    //@@author A0139661Y
	/**
     * Checks if the detail input is valid, as in, it must not be blank.
     * This is used in conjunction with {@link #extractDetailForEdit()}.
     *
     * @throws IllegalValueException if only one ' found, or if detail is blank.
     */
	private boolean checkValidDetailInputForEdit() throws IllegalValueException {
    	// Check if only one ' used
    	if (args.lastIndexOf("'") == args.indexOf("'"))
    		return false;
    	// Check if detail is empty.
    	if (args.lastIndexOf("'") == args.indexOf("'")+1)
    		throw new IllegalValueException(MESSAGE_BLANK_DETAIL_WARNING);
    	return true;
	}

    /**
     * Extracts the new task's tags from the add command's tag arguments string.
     * Merges duplicate tag strings.
     *
     * @throws IllegalValueException if tag input is invalid.
     */
    private static Set<String> getTagsFromArgs() throws IllegalValueException {
    	List<String> rawArgs = Arrays.asList(splittedArgs);
    	Collection<String> tagStrings = new ArrayList<String>();
    	boolean isEmpty = true;
    	for (String rawArg : rawArgs) {
    		isEmpty = false;
    		if (rawArg.startsWith("-")) {
    			tagStrings.add(rawArg.replace("-", ""));
    		}
    	}
    	if (isEmpty) {
    		return Collections.emptySet();
    	}
    	return new HashSet<>(tagStrings);
    }

    //@@author A0139661Y
    /**
     * Utility method which replaces all redundant spaces
     *
     * @param args an uncleaan string
     * @return a cleaned up string
     */
    private String getCleanString(String args) {
    	return args.trim().replaceAll("\\s+", " ");
    }

    //@@author A0138471A
    private String convertToTo(String args) {
    	return args.replaceAll(" - ", " to ");
    }

    /**
     * Returns the specified index in the {@code command} IF a positive unsigned integer is given as the index.
     * The index here does not precede anything.
	 *
     * @return {@code Optional.empty()} otherwise.
     */
    private Optional<Integer> parseIndex(String command) {
        final Matcher matcher = TASK_INDEX_ARGS_FORMAT.matcher(command.trim());
        if (!matcher.matches()) {
            return Optional.empty();
        }

        String index = matcher.group("targetIndex");
        if(!StringUtil.isUnsignedInteger(index)){
            return Optional.empty();
        }
        return Optional.of(Integer.parseInt(index));
    }

    //@@author A0139661Y
    /**
     * Returns the specified index in the {@code command} IF a positive unsigned integer is given as the index.
     * An index is loose if there are arguments after the index.
     *
     * @return {@code Optional.empty()} otherwise.
     */
    private Optional<Integer> parseLooseIndex(String command) {
        final Matcher matcher = TASK_LOOSE_INDEX_ARGS_FORMAT.matcher(command.trim());
        if (!matcher.matches()) {
            return Optional.empty();
        }

        String index = matcher.group("targetIndex");
        if(!StringUtil.isUnsignedInteger(index)){
            return Optional.empty();
        }
        return Optional.of(Integer.parseInt(index));
    }

	//@@author A0139661Y
    /**
	 * Checks for accidental '/' instead of ' /'.
	 *
	 * @throws IllegalValueException
	 */
    private void checkPriorityValidity() throws IllegalValueException {
    	if (args.contains("/") && !args.contains(" /"))
    		throw new IllegalValueException(Messages.MESSAGE_INVALID_PRIORITY_SPACE);
	}

    //@@author A0139661Y
    /**
     * Checks if the user wants to edit time or priority.
     * Used in conjunction with {@link #prepareEdit()}
     */
    private void checkSpecialRequestInEdit() {
        //if keyword float is entered, it becomes a floating task (no date no time)
        if(args.toLowerCase().contains("floating") || args.toLowerCase().contains("fl")){
        	floatingRequestInEdit = true;
        }
        //if keyword is only, we take it that the user means to have a single time or date.
        else if (args.toLowerCase().contains("only")) {
        	onlyOneDateOrTimeRequestInEdit = true;
        }
        //if keyword rp or remove priority is entered, priority is removed
        if(args.toLowerCase().contains("no priority") || args.toLowerCase().contains("np")) {
        	priorityRequestInEdit = true;
        }

    }

    //@@author A0139661Y
    /**
     * Tests to see if command ends in an index.
     *
     * @return boolean indicative of where index is present
     */
    private boolean isIndexInCommandPresent() {
    	Optional<Integer> checkForIndex = parseIndex(args);
    	if (!checkForIndex.isPresent())
    		return false;
    	targetIndex = checkForIndex.get();
    	return true;
    }

    //@@author A0139661Y
    /**
     * Tests to see if command ends in a loose index.
     * A loose index is an index with proceeding strings.
     *
     * @return boolean indicative of where loose index is present
     */
    private boolean isLooseIndexInCommandPresent() {
    	Optional<Integer> checkForIndex = parseLooseIndex(args);
    	if (!checkForIndex.isPresent())
    		return false;
    	targetIndex = checkForIndex.get();
    	return true;
    }

	//@@author A0139661Y
    /**
	 * Saves the date and time from list to dt family according to the following table
	 *
	 * ______________________
	 * | type 	| condition	|
	 * ----------------------
	 * | 0		| no DT		|
	 * | 1		| single DT	|
	 * | 2		| two DT	|
	 * ======================
	 */
    private void saveDueByDateAndTime() {
    	if (datesAndTimes.size() == 1) {
    		dt = datesAndTimes.get(0);
    		dateTimeType = 1;
    	} else if (datesAndTimes.size() == 2) {
    		dtStart = datesAndTimes.get(0);
    		dtEnd = datesAndTimes.get(1);
    		dateTimeType = 2;
    	} else {
    		dt = LocalDateTime.of(NO_DATE_DEFAULT, NO_TIME_DEFAULT);
    		dateTimeType = 0;
    	}
	}

    //@@author A0139661Y
    /**
     * Overrides the DBD and DBT when editing or adding a block task.
     * This is to comply with the constraints specified for blocks.
     *
     * @throws IllegalValueException
     */
    private void overrideDueByDateAndTimeForBlock() throws IllegalValueException {
		// Override saveDueByDateAndTime()
    	if (dateTimeType == 0) {
    		throw new IllegalValueException("Specify a time/date range for the block.");
    	}
    	// Only one time or date or both
    	if (dateTimeType == 1) {
    		// Case 1: Date only
    		if (dt.toLocalTime().equals(NO_TIME_DEFAULT)) {
    			dtStart = dt;
    			dtEnd = dt;
    		} else {
        		// Case 2: Time only or date and time only
    			dtStart = dt;
    			dtEnd = dt.plusHours(1);
    		}
			dt = NO_DATETIME_DEFAULT;
    	}
    }

    //@@author A0139661Y
	private void reset() {
        datesAndTimes.clear();
        args = EMPTY_STRING;
        floatingRequestInEdit = false;
        priorityRequestInEdit = false;
	}

	//@@author A0138471A-unused
//  private void extractDetailUnused() throws IllegalValueException {
//  	checkValidDetailInput();
//  	// Split into '  ...  '
//  	String[] details = args.split("^ '(.+)'$");
//  	// Details only, get rid of anything after the '
//  	String output = new StringBuilder(details[0]).replace(details[0].lastIndexOf("'"),
// 													details[0].length(),
// 													"").toString();
//      // Details only, get rid of anything before the '
//      for(char o : output.toCharArray()) {
//      	if(o =='\'') {
//      		break;
//      	}
//      	else
//      		output=output.replaceFirst(".", "");
//      }
//      // Get rid of the first '
//      output = output.replaceFirst("'","");
//      // Save to instance
//      detailToAdd = output;
//  	// return rear end
//  	args = new StringBuilder(details[0]).substring(details[0].lastIndexOf("'")+1).toString();
//  	// return args without details
//  	args = args.replace(output, "");
//    }

}


text:
<?php

namespace Cocorico\CoreBundle\Model\Manager;

use Cocorico\CoreBundle\Document\ListingAvailability;
use Cocorico\CoreBundle\Entity\Booking;
use Cocorico\CoreBundle\Entity\Listing;
use Cocorico\CoreBundle\Event\BookingEvent;
use Cocorico\CoreBundle\Event\BookingEvents;
use Cocorico\CoreBundle\Event\BookingPayinRefundEvent;
use Cocorico\CoreBundle\Event\BookingValidateEvent;
use Cocorico\CoreBundle\Mailer\TwigSwiftMailer;
use Cocorico\CoreBundle\Model\DateRange;
use Cocorico\CoreBundle\Model\TimeRange;
use Cocorico\CoreBundle\Repository\BookingRepository;
use Cocorico\CoreBundle\Repository\ListingDiscountRepository;
use Cocorico\CoreBundle\Smser\TwigSmser;
use Cocorico\GeoBundle\DistanceMatrix\DistanceMatrix;
use Cocorico\GeoBundle\DistanceMatrix\DistanceMatrixRequest;
use Cocorico\UserBundle\Entity\User;
use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Query;
use Doctrine\ORM\Tools\Pagination\Paginator;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

class BookingManager extends BaseManager
{
    protected $em;
    protected $dm;
    protected $feeAsAsker;
    protected $feeAsOfferer;
    protected $endDayIncluded;
    protected $timeUnit;
    protected $timeUnitIsDay;
    protected $timesMax;
    protected $minStartDelay;
    protected $minStartTimeDelay;
    public $minPrice;
    protected $listingAvailabilityManager;
    public $maxPerPage;
    protected $mailer;
    protected $smser;
    protected $smsReceiver;
    /** @var \Cocorico\ListingOptionBundle\Model\Manager\OptionManager $optionManager */
    protected $optionManager;
    /** @var \Cocorico\VoucherBundle\Model\Manager\VoucherManager $voucherManager */
    public $voucherManager;
    protected $defaultListingStatus;
    protected $vatRate;
    protected $includeVat;
    protected $dispatcher;

    /**
     * @param EntityManager                                              $em
     * @param DocumentManager                                            $dm
     * @param float                                                      $feeAsAsker
     * @param float                                                      $feeAsOfferer
     * @param boolean                                                    $endDayIncluded
     * @param int                                                        $timeUnit App time unit in minutes
     * @param int                                                        $timesMax Max times unit if time_unit is not day
     * @param int                                                        $minStartDelay
     * @param int                                                        $minStartTimeDelay
     * @param int                                                        $minPrice
     * @param ListingAvailabilityManager                                 $listingAvailabilityManager
     * @param int                                                        $maxPerPage
     * @param TwigSwiftMailer                                            $mailer
     * @param TwigSmser                                                  $smser
     * @param                                                            $smsReceiver
     * @param                                                            $optionManager
     * @param                                                            $voucherManager
     * @param int                                                        $defaultListingStatus
     * @param float                                                      $vatRate
     * @param bool                                                       $includeVat
     * @param EventDispatcherInterface                                   $dispatcher
     */
    public function __construct(
        EntityManager $em,
        DocumentManager $dm,
        $feeAsAsker,
        $feeAsOfferer,
        $endDayIncluded,
        $timeUnit,
        $timesMax,
        $minStartDelay,
        $minStartTimeDelay,
        $minPrice,
        ListingAvailabilityManager $listingAvailabilityManager,
        $maxPerPage,
        TwigSwiftMailer $mailer,
        TwigSmser $smser,
        $smsReceiver,
        $optionManager,
        $voucherManager,
        $defaultListingStatus,
        $vatRate,
        $includeVat,
        EventDispatcherInterface $dispatcher
    ) {
        $this->em = $em;
        $this->dm = $dm;
        $this->feeAsAsker = $feeAsAsker;
        $this->feeAsOfferer = $feeAsOfferer;
        $this->endDayIncluded = $endDayIncluded;
        $this->timeUnit = $timeUnit;
        $this->timeUnitIsDay = ($timeUnit % 1440 == 0) ? true : false;
        $this->timesMax = $timesMax;
        $this->minStartDelay = $minStartDelay;
        $this->minStartTimeDelay = $minStartTimeDelay;
        $this->minPrice = $minPrice;
        $this->listingAvailabilityManager = $listingAvailabilityManager;
        $this->maxPerPage = $maxPerPage;
        $this->mailer = $mailer;
        $this->smser = $smser;
        $this->smsReceiver = $smsReceiver;
        $this->optionManager = $optionManager;
        $this->voucherManager = $voucherManager;
        $this->defaultListingStatus = $defaultListingStatus;
        $this->vatRate = $vatRate;
        $this->includeVat = $includeVat;
        $this->dispatcher = $dispatcher;
    }

    /**
     * Pre-set new Booking based data.
     *
     * @param Listing           $listing
     * @param User|null         $user
     * @param DateRange         $dateRange
     * @param TimeRange|boolean $timeRange
     * @return Booking
     */
    public function initBooking(Listing $listing, $user, DateRange $dateRange = null, $timeRange = null)
    {
        $booking = new Booking();
        $booking->setListing($listing);
        $booking->setUser($user);
        $booking->setStatus(Booking::STATUS_DRAFT);

        if ($dateRange && $dateRange->getStart() && $dateRange->getEnd()) {
            $dateRange->getStart()->setTime(0, 0, 0);
            $dateRange->getEnd()->setTime(0, 0, 0);
            $booking->setStart($dateRange->getStart());
            $booking->setEnd($dateRange->getEnd());
        }

        if (!$this->timeUnitIsDay) {
            if ($timeRange && $timeRange->getStart() && $timeRange->getEnd()) {
                $booking->setStartTime($timeRange->getStart());
                $booking->setEndTime($timeRange->getEnd());
            }
        } else {
            $booking->setStartTime(new \DateTime('1970-01-01 00:00'));
            $booking->setEndTime(new \DateTime('1970-01-01 00:00'));
        }

        $booking->setCancellationPolicy($listing->getCancellationPolicy());

        return $booking;
    }

    /**
     * Check Booking Availability And Set Booking Amounts if no error.
     * Return the following errors if any :
     *  - self_booking_invalid => listing can not be booked by listing owner
     *  - unavailable => listing is unavailable
     *  - duration_invalid => booking duration is invalid
     *  - see checkBookingDates returns
     *
     * @param Booking $booking
     *
     * @return array errors
     * @throws \Exception
     */
    public function checkBookingAvailabilityAndSetAmounts(Booking &$booking)
    {
        $amount = 0;
        $errors = $this->checkBookingDates($booking);

        if (count($errors)) {
            return $errors;
        }
        $listing = $booking->getListing();
        $listingAvailabilityRepository = $this->dm->getRepository('CocoricoCoreBundle:ListingAvailability');
        $listingAvailabilities = $listingAvailabilityRepository->getAvailabilitiesByListingAndDateRange(
            $listing->getId(),
            $booking->getStart(),
            $booking->getEnd(),
            $this->endDayIncluded,
            false
        );
        //echo "nb listingAvailabilities" . $listingAvailabilities->count() . "
";

        $bookingDuration = $booking->getDuration($this->endDayIncluded, $this->timeUnit);

        //echo "bookingDuration" . $bookingDuration . "
";
        //Invalid duration
        if ($bookingDuration === false
            || ($listing->getMinDuration() && $bookingDuration < $listing->getMinDuration())
            || ($listing->getMaxDuration() && $bookingDuration > $listing->getMaxDuration())
            || $bookingDuration <= 0
        ) {
            $errors[] = 'duration_invalid';
        } //Unavailable
        elseif (
            $this->defaultListingStatus == ListingAvailability::STATUS_UNAVAILABLE
            && !$listingAvailabilities->count()
        ) {
            $errors[] = 'unavailable';
        } else {
            $price = $listing->getPrice();
            $amount = $bookingDuration * $price;
            $amountByMinute = $price / $this->timeUnit;
            foreach ($listingAvailabilities as $listingAvailability) {
                //Listing availability
                if ($this->getTimeUnitIsDay()) {
                    //Availability
                    if (count($errors) ||
                        $listingAvailability["s"] == ListingAvailability::STATUS_UNAVAILABLE ||
                        $listingAvailability["s"] == ListingAvailability::STATUS_BOOKED
                    ) {
                        $amount = 0;
                        $errors[] = 'unavailable';
                        break;
                    }
                    $amount -= $price;
                    $amount += $listingAvailability["p"];
                } else {
                    if (count($errors)) {
                        break;
                    }

                    if (!isset($listingAvailability["ts"])) {
                        throw new \Exception(
                            "Time unit application parameter seems to have been changed from day to hour(s)."
                        );
                    }
                    //Compute amount from existing times
                    $existingTimes = $listingAvailability["ts"];
                    //echo "existingTimes" . print_r($existingTimes, 1) . "
";

                    $times = array();
                    foreach ($existingTimes as $l => $existingTime) {
                        $times[intval($existingTime["_id"])] = $existingTime;
                    }

                    $startMinute = intval($booking->getStartTime()->getTimestamp() / 60);
                    $nbMinutes = intval(
                        ($booking->getEndTime()->getTimestamp() - $booking->getStartTime()->getTimestamp()) / 60
                    );
                    $nbMinutes += $startMinute;

                    //Price defined for each minute are defined for one time unit (hour, ...)
                    for ($k = $startMinute; $k < $nbMinutes; $k++) {
                        //If price is defined for this minute,
                        if (isset($times[$k])) {
                            if ($times[$k]["s"] == ListingAvailability::STATUS_UNAVAILABLE ||
                                $times[$k]["s"] == ListingAvailability::STATUS_BOOKED
                            ) {
                                $amount = 0;
                                $errors[] = 'unavailable';
                                break;
                            }
                            //We add to amount the corresponding price reported to one minute
                            $amount -= $amountByMinute;
                            $amount += $times[$k]["p"] / $this->timeUnit;
                        } else {
                            //We add to amount the price for the corresponding day reported to one minute
                            $amount -= $amountByMinute;
                            $amount += $listing->getPrice() / $this->timeUnit;
                        }
                    }

                }
            }
        }

        if (!count($errors)) {
            if ($this->deliveryIsEnabled()) {
                //Shipping cost
                $result = $this->applyDeliveryOnBooking($booking);
                $booking = $result['booking'];
                $errors[] = $result['error'];
                if (!$result['error']) {
                    $amount += $booking->getAmountDelivery();
                }
            }

            //Discount
            /** @var ListingDiscountRepository $listingDiscountRepository */
            $listingDiscountRepository = $this->em->getRepository("CocoricoCoreBundle:ListingDiscount");
            $discount = $listingDiscountRepository->findOneByFromQuantity($listing->getId(), $bookingDuration);

            if ($discount) {
                $amount -= ($discount->getDiscount() / 100) * $amount;
            }

            if ($amount <= 0 || $amount < $this->minPrice) {
                $errors[] = 'amount_invalid';
            } else {
                /**
                 * Options
                 * Options amount is added to amount to pay by asker
                 * No discount on Options amount
                 * Fees are taken on options amount
                 *
                 */
                if ($this->optionIsEnabled() && $booking->getOptions()) {
                    $amountOptions = $this->optionManager->getBookingOptionsAmount($booking);
                    $booking->setAmountOptions($amountOptions);
                    $amount = $amount + $booking->getAmountOptions();
                }

                //Booking amount and fees are setted here
                $booking = $this->setBookingAmounts($booking, $amount);

                /**
                 * Voucher
                 * Voucher amount is substracted from amount to pay to asker.
                 *
                 * Fees still the same
                 */
                if ($this->voucherIsEnabled() && $booking->getCodeVoucher()) {
                    $result = $this->applyVoucherOnBooking($booking);
                    /** @var Booking $booking */
                    $booking = $result['booking'];
                    $errors[] = $result['error'];
//                    $amount = max($booking->getAmountToPayByAsker() - $booking->getAmountDiscountVoucher(), $this->minPrice);
//                    $booking = $this->setBookingAmounts($booking, $amount);
                }
            }
        }

        return $errors;
    }

    /**
     * //todo: decouple delivery
     *
     * Apply delivery constraint on Booking: Set delivery amount and distance or return error if any
     *
     * @param Booking $booking
     * @return Booking[]|string
     *      ['booking']              Booking
     *      ['error']                string ('delivery_max_invalid' or 'delivery_invalid') in case of error
     */
    private function applyDeliveryOnBooking(Booking $booking)
    {
        $result = array('booking' => $booking, 'error' => '');

        $listing = $booking->getListing();

        if ($booking->getDelivery() && $booking->getDeliveryAddress()) {
            if ($listing->getPriceDelivery()) {
                $coordinate = $listing->getLocation()->getCoordinate();
                $origins = array($coordinate->getLat() . ',' . $coordinate->getLng());
                $destinations = array($booking->getDeliveryAddress());

                try {
                    $distanceMatrixRequest = new DistanceMatrixRequest($origins, $destinations);
                    $distanceMatrixRequest->setTravelMode(DistanceMatrix::TRAVEL_DRIVING);
                    $distanceMatrix = new DistanceMatrix();
                    $response = $distanceMatrix->process($distanceMatrixRequest);

                    $origins = $response->getOrigins();

                    for ($i = 0; $i < count($origins); $i++) {
                        $rows = $response->getRows();
                        $elements = $rows[$i]->getElements();

                        for ($j = 0; $j < count($elements); $j++) {
                            $element = $elements[$j];
                            if ($element->getStatus() == DistanceMatrix::STATUS_OK) {
                                $distance = $element->getDistance();
                                $distanceInKm = $distance->getValue() / 1000;

                                $amountDelivery = $distanceInKm * $listing->getPriceDelivery();
                                $amountDelivery = $amountDelivery > 0 ? $amountDelivery : 0;
                                if ($distanceInKm <= $listing->getKilometerMax()) {
                                    if ($distanceInKm > $listing->getKilometerMin()) {
                                        $booking->setAmountDelivery($amountDelivery);
                                    } else {
                                        $booking->setAmountDelivery(0);
                                    }
                                    $booking->setDistanceDelivery($distance->getValue());
                                } else {
                                    $result['error'] = 'delivery_max_invalid';
                                }
                            } else {
                                $result['error'] = 'delivery_invalid';
                            }
                        }
                    }
                } catch (\Exception $e) {
                    $result['error'] = 'delivery_invalid';
                }
            } else {
                $booking->setAmountDelivery(0);
            }
        }

        $result['booking'] = $booking;

        return $result;
    }

    /**
     * //todo: decouple voucher
     * Apply voucher on booking amount : Modify booking amount or return error type if any
     *
     * array['booking']              Booking
     *      ['error']                string ('amount_voucher_invalid' or 'voucher_invalid') in case of error
     *
     * @param Booking $booking
     * @return array (See above)
     */
    public function applyVoucherOnBooking(Booking $booking)
    {
        $result = array('booking' => $booking, 'error' => '');

        $bookingAmount = $booking->getAmountToPayByAsker();

        $voucher = $this->voucherManager->getRepository()->findValidVoucher(
            $booking->getCodeVoucher(),
            $bookingAmount
        );

        if ($voucher) {
            $discountAmount = $this->voucherManager->getDiscountAmount(
                $bookingAmount,
                $voucher->getDiscountType(),
                $voucher->getDiscount()
            );

            if ($discountAmount) {
                $amountToPay = $bookingAmount - $discountAmount;
                //Si le montant de la resa apres reduction est inferieur au prix minimum d'une resa
                //Le montant de la resa devient celui du prix miminum
                if ($amountToPay < $this->minPrice) {
//                    $amountToPay = $this->minPrice;
//                    $booking->setAmountFeeAsAsker(0);
//                    $booking->setAmountFeeAsOfferer(0);
                    $result['error'] = 'amount_voucher_invalid';
                } else {
                    //Si le montant de la reduction est superieur au montant des commissions demandeur
                    //le montant des commissions demandeur devient 0
                    //sinon le montant des commissions demandeur est egale a la commission demandeur moins le montant de la reduction
                    if ($discountAmount >= $booking->getAmountFeeAsAsker()) {
                        $booking->setAmountFeeAsAsker(0);
                    } else {
                        $booking->setAmountFeeAsAsker($booking->getAmountFeeAsAsker() - $discountAmount);
                    }

                    //Si le montant à payer est inferieur aux commissions offreur
                    //Alors le montant des commissions offreur devient 0
                    if ($amountToPay <= $booking->getAmountFeeAsOfferer()) {
//                        $booking->setAmountFeeAsOfferer(0);
                        $result['error'] = 'amount_voucher_invalid';
                    } else {
                        //
                    }
                }

                if (!$result['error']) {
                    $booking->setAmountTotal($amountToPay);
                    $booking->setAmountDiscountVoucher($bookingAmount - $amountToPay);
                    $booking->setDiscountVoucher($voucher->getDiscount());//Memorize discount voucher value to booking
                } else {
                    $booking->setAmountTotal(0);
                    $booking->setDiscountVoucher(null);
                    $booking->setAmountDiscountVoucher(null);
                }

//                $this->logBookingAmounts($booking);
            }
        } else {
            $result['error'] = 'code_voucher_invalid';
        }

        $result['booking'] = $booking;

        return $result;
    }

//    private function logBookingAmounts(Booking $booking)
//    {
//       echo "booking->amount:" . $booking->getAmount() . "
";
//        echo "booking->amountTotal:" . $booking->getAmountTotal() . "
";
//        echo "booking->amountFeeAsAsker:" . $booking->getAmountFeeAsAsker() . "
";
//        echo "booking->amountFeeAsOfferer:" . $booking->getAmountFeeAsOfferer() . "
";
//        echo "booking->amountDiscountVoucher:" . $booking->getAmountDiscountVoucher() . "
";
//    }

    /**
     * //todo: Check factorization with DateRangeValidator->onPostBind
     * Check if booking dates are correct:
     *  Return :
     *      - date_range.invalid.min_start if start date is incorrect (start is greater than today plus minStartDelay days)
     *      - date_range.invalid.max_end if end date is incorrect (More than one year later)
     *      - date_range.invalid.end_before_start if start is after end
     *      - time_range.invalid.end_before_start if start time is after end
     *      - time_range.invalid.single_time if start time = end time
     *      - time_range.invalid.duration if duration > to max times unit (maxTimes)
     *      - time_range.invalid.min_start if start time is incorrect (start time is greater than today plus minStartTimeDelay hours)
     *
     * Errors are translated in DateRangeValidator and TimeRangeValidator
     *
     * @param Booking $booking
     *
     * @return array errors
     */
    protected function checkBookingDates(Booking $booking)
    {
        $errors = array();

        $now = new \DateTime();
        if ($this->minStartDelay > 0) {
            $now->add(new \DateInterval('P' . $this->minStartDelay . 'D'));
        }

        if ($booking->getStart()) {
            $interval = $now->diff($booking->getStart())->format('%r%a');
            if ($interval < 0) {
                $errors[] = 'date_range.invalid.min_start';
            }

            $oneYearLater = $now->add(new \DateInterval('P1Y'));
            if ($booking->getEnd() > $oneYearLater) {
                $errors[] = 'date_range.invalid.max_end';
            }

            if ($booking->getStart() > $booking->getEnd()) {
                $errors[] = 'date_range.invalid.end_before_start';
            }

            if (!$this->timeUnitIsDay) {
                if (!$booking->getStartTime() || !$booking->getEndTime()) {
                    $errors[] = 'time_range.invalid.required';
                }
                if ($booking->getStartTime() > $booking->getEndTime()) {
                    $errors[] = 'time_range.invalid.end_before_start';
                } elseif ($booking->getStartTime() == $booking->getEndTime()) {
                    $errors[] = 'time_range.invalid.single_time';
                }

                if ($booking->getStartTime() && $booking->getEndTime()) {
                    $timeRange = new TimeRange($booking->getStartTime(), $booking->getEndTime());
                    $duration = $timeRange->getDuration($this->timeUnit);
                    if ($duration > $this->timesMax || !$duration) {
                        $errors[] = 'time_range.invalid.duration';
                    }

                    if (!$booking->hasCorrectStartTime(
                        $this->minStartDelay,
                        $this->minStartTimeDelay,
                        $this->getTimeUnitIsDay()
                    )
                    ) {
                        $errors[] = 'time_range.invalid.min_start';
                    }
                }
            }

        }

        return $errors;
    }

    /**
     * Set all related booking amounts (booking amount, fee as asker and offerer)
     *
     * @param Booking $booking
     * @param  int    $amount
     *
     * @return Booking
     */
    public function setBookingAmounts(Booking $booking, $amount)
    {
        if ($amount > 0) {
            //If VAT is not included in listing prices fixing then VAT amount is added here
            if (!$this->includeVat) {
                $amount += $amount * $this->vatRate;
            }

            //Amounts
            $booking->setAmount(round($amount));

            //Fees computation Asker
            $asker = $booking->getUser();
            $booking->setAmountFeeAsAsker($this->feeAsAsker * $amount);
            //If user has a custom fee defined we use it
            if ($asker) {
                $feeAsAsker = $asker->getFeeAsAsker();
                if ($feeAsAsker || $feeAsAsker === 0) {
                    $booking->setAmountFeeAsAsker(($feeAsAsker / 100) * $amount);
                }
            }

            //Fees computation Offerer
            $offerer = $booking->getListing()->getUser();
            $booking->setAmountFeeAsOfferer($this->feeAsOfferer * $amount);
            //If user has a custom fee defined we use it
            if ($offerer) {
                $feeAsOfferer = $offerer->getFeeAsOfferer();
                if ($feeAsOfferer || $feeAsOfferer === 0) {
                    $booking->setAmountFeeAsOfferer(($feeAsOfferer / 100) * $amount);
                }
            }

            //Round cents with decimal
            $booking->setAmountFeeAsAsker(round($booking->getAmountFeeAsAsker()));
            $booking->setAmountFeeAsOfferer(round($booking->getAmountFeeAsOfferer()));

            $booking->setAmountTotal($booking->getAmount() + $booking->getAmountFeeAsAsker());
        }

        return $booking;
    }

    /**
     * @param int    $askerId
     * @param string $locale
     * @param int    $page
     * @param array  $status
     *
     * @return Paginator
     */
    public function findByAsker($askerId, $locale, $page, $status = array())
    {
        $queryBuilder = $this->getRepository()->getFindByAskerQuery($askerId, $locale, $status);

        //Pagination
        $queryBuilder
            ->setFirstResult(($page - 1) * $this->maxPerPage)
            ->setMaxResults($this->maxPerPage);

        //Query
        $query = $queryBuilder->getQuery();

        return new Paginator($query);
    }

    /**
     * @param int    $askerId
     * @param string $locale
     * @param int    $page
     * @param array  $status
     *
     * @return Paginator
     */
    public function findPayedByAsker($askerId, $locale, $page, $status = array())
    {
        $queryBuilder = $this->getRepository()->getFindByAskerQuery($askerId, $locale, $status);

        $queryBuilder
            ->andWhere('b.payedBookingAt IS NOT NULL');

        if ($this->mangopayIsEnabled()) {
            $queryBuilder
                ->andWhere('b.mangopayPayinPreAuthId IS NOT NULL');
        }

        //Pagination
        $queryBuilder
            ->setFirstResult(($page - 1) * $this->maxPerPage)
            ->setMaxResults($this->maxPerPage);

        //Query
        $query = $queryBuilder->getQuery();

        return new Paginator($query);
    }

    /**
     * @param  int    $offererId
     * @param  string $locale
     * @param  int    $page
     * @param  array  $status
     * @return Paginator
     */
    public function findByOfferer($offererId, $locale, $page, $status = array())
    {
        $queryBuilder = $this->getRepository()->getFindByOffererQuery($offererId, $locale, $status);

        //Pagination
        $queryBuilder
            ->setFirstResult(($page - 1) * $this->maxPerPage)
            ->setMaxResults($this->maxPerPage);

        //Query
        $query = $queryBuilder->getQuery();

        return new Paginator($query);
    }

    /**
     * @param int    $id
     * @param int    $askerId
     * @param string $locale
     * @param array  $status
     *
     * @return Booking|null
     *
     * @throws \Doctrine\ORM\NonUniqueResultException
     */
    public function findOneByAsker($id, $askerId, $locale, $status = array())
    {
        $queryBuilder = $this->getRepository()->getFindOneByAskerQuery($id, $askerId, $locale, $status);

        $query = $queryBuilder->getQuery();

        return $query->getOneOrNullResult();
    }

    /**
     * Create a new booking
     *
     * @param Booking $booking
     * @return Booking|false
     */
    public function create(Booking $booking)
    {
        if (in_array($booking->getStatus(), Booking::$newableStatus)) {
            //New Booking confirmation
            $booking->setStatus(Booking::STATUS_NEW);
            $booking->setNewBookingAt(new \DateTime());
            $booking = $this->save($booking);

            //Voucher use
            if ($this->voucherIsEnabled()) {
                $this->voucherManager->checkVoucherUse($booking);
            }

            $this->mailer->sendBookingRequestMessageToOfferer($booking);
            $this->mailer->sendBookingRequestMessageToAsker($booking);

            $this->smser->sendBookingRequestMessageToOfferer($booking);

            return $booking;
        }

        return false;
    }

    /**
     * Alert Expiring Bookings
     *
     * @param int $expirationDelay
     * @param int $alertExpirationDelay
     *
     * @return integer
     */
    public function alertExpiringBookings($expirationDelay, $alertExpirationDelay)
    {
        $result = 0;
        $bookingsExpiringToAlert = $this->getRepository()->findBookingsExpiringToAlert(
            $expirationDelay,
            $alertExpirationDelay
        );
        foreach ($bookingsExpiringToAlert as $bookingExpiringToAlert) {
            if ($this->alertExpiring($bookingExpiringToAlert)) {
                $result++;
            }
        }

        return $result;
    }

    /**
     * Alert Expiring Booking
     *
     * @param Booking $booking
     *
     * @return bool
     */
    public function alertExpiring(Booking $booking)
    {
        if (in_array($booking->getStatus(), Booking::$expirableStatus)) {
            $booking->setAlertedExpiring(true);
            $booking = $this->save($booking);
            //Mail offerer
            $this->mailer->sendBookingExpirationAlertMessageToOfferer($booking);
            $this->smser->sendBookingExpirationAlertMessageToOfferer($booking);

            return true;
        }

        return false;
    }

    /**
     * Expire Bookings
     *
     * @param int $expirationDelay
     *
     * @return integer
     */
    public function expireBookings($expirationDelay)
    {
        $result = 0;
        $bookingsToExpire = $this->getRepository()->findBookingsToExpire($expirationDelay);
        foreach ($bookingsToExpire as $bookingToExpire) {
            if ($this->expire($bookingToExpire)) {
                $result++;
            }
        }

        return $result;
    }

    /**
     * Expire Booking
     *
     * @param Booking $booking
     *
     * @return bool
     */
    public function expire(Booking $booking)
    {
        if (in_array($booking->getStatus(), Booking::$expirableStatus)) {
            $booking->setStatus(Booking::STATUS_EXPIRED);
            $booking = $this->save($booking);
            //Mail offerer
            $this->mailer->sendBookingRequestExpiredMessageToOfferer($booking);
            $this->smser->sendBookingRequestExpiredMessageToOfferer($booking);
            //Mail asker
            $this->mailer->sendBookingRequestExpiredMessageToAsker($booking);
            $this->smser->sendBookingRequestExpiredMessageToAsker($booking);

            return true;
        }

        return false;
    }

    /**
     * Alert Imminent Bookings
     *
     * @param int $imminentDelay
     *
     * @return integer
     */
    public function alertImminentBookings($imminentDelay)
    {
        $result = 0;
        $bookingsImminentToAlert = $this->getRepository()->findBookingsImminentToAlert(
            $imminentDelay
        );
        foreach ($bookingsImminentToAlert as $bookingImminentToAlert) {
            if ($this->alertImminent($bookingImminentToAlert)) {
                $result++;
            }
        }

        return $result;
    }

    /**
     * Alert imminent Booking
     *
     * @param Booking $booking
     *
     * @return bool
     */
    public function alertImminent(Booking $booking)
    {
        if (in_array($booking->getStatus(), Booking::$validatableStatus)) {
            $booking->setAlertedImminent(true);
            $booking = $this->save($booking);
            //Mail offerer
            $this->mailer->sendBookingImminentMessageToOfferer($booking);
            $this->smser->sendBookingImminentMessageToOfferer($booking);
            //Mail asker
            $this->mailer->sendBookingImminentMessageToAsker($booking);
            $this->smser->sendBookingImminentMessageToAsker($booking);

            return true;
        }

        return false;
    }

    /**
     * Pay booking (when offerer accept)
     *
     *  Set listing availabilities status as booked
     *  Set booking status as payed
     *  Send mails
     *
     * @param Booking $booking
     *
     * @return Booking|bool
     */
    public function pay(Booking $booking)
    {
        if (in_array($booking->getStatus(), Booking::$payableStatus)) {
            try {
                $event = new BookingEvent($booking);
                $this->dispatcher->dispatch(BookingEvents::BOOKING_PAY, $event);//Payment is done here
                $booking = $event->getBooking();

                $booking->setStatus(Booking::STATUS_PAYED);
                $booking->setPayedBookingAt(new \DateTime());
                $booking = $this->save($booking);

                $listing = $booking->getListing();

                $this->listingAvailabilityManager->saveAvailabilitiesStatus(
                    $listing->getId(),
                    new DateRange($booking->getStart(), $booking->getEnd()),
                    array(),
                    $this->timeUnitIsDay ? array() : array(
                        new TimeRange($booking->getStartTime(), $booking->getEndTime())
                    ),
                    ListingAvailability::STATUS_BOOKED,
                    $listing->getPrice(),
                    $this->endDayIncluded,
                    false
                );

                $this->mailer->sendBookingAcceptedMessageToAsker($booking);
                $this->mailer->sendBookingAcceptedMessageToOfferer($booking);
                $this->smser->sendBookingAcceptedMessageToAsker($booking);

                //Refuse other booking requests existing in this booking date range
                $bookingsToRefuse = $this->getRepository()->findBookingsToRefuse(
                    $booking,
                    $this->endDayIncluded,
                    $this->timeUnitIsDay
                );
                foreach ($bookingsToRefuse as $bookingToRefuse) {
                    $this->refuse($bookingToRefuse);
                }

                return $booking;
            } catch (\Exception $e) {
                //In case of error while payment for example
                return false;
            }
        }

        return false;
    }

    /**
     * Offerer refuse booking :
     *  Set booking status as refused
     *  Send mails
     *
     * @param Booking $booking
     *
     * @return Booking|bool
     */
    public function refuse(Booking $booking)
    {
        if (in_array($booking->getStatus(), Booking::$refusableStatus)) {
            $booking->setStatus(Booking::STATUS_REFUSED);
            $booking->setRefusedBookingAt(new \DateTime());
            $booking = $this->save($booking);

            $this->mailer->sendBookingRefusedMessageToAsker($booking);
            $this->smser->sendBookingRefusedMessageToAsker($booking);

            $this->mailer->sendBookingRefusedMessageToOfferer($booking);

            return $booking;
        }

        return false;
    }

    /**
     * Validate Booking. The offerer can be payed.
     * Is the booking object considered as validated (Offerer can be payed) after booking start date or booking end date.
     *
     * @param string $validatedMoment 'start' or 'end'*
     * @param int    $validatedDelay  Time after or before the moment the booking is considered as validated (in minutes)
     *
     * @return int
     */
    public function validateBookings($validatedMoment, $validatedDelay)
    {
        $result = 0;
        $bookingsToValidate = $this->getRepository()->findBookingsToValidate(
            $validatedMoment,
            $validatedDelay
        );
        foreach ($bookingsToValidate as $bookingToValidate) {
            if ($this->validate($bookingToValidate)) {
                $result++;
            }
        }

        return $result;
    }

    /**
     * Validate Booking:
     *  Transfer the funds from the asker's wallet to the offerer's wallet.
     *  The offerer can be payed.
     *  Platform fees are taken here.
     *
     * @param Booking $booking
     *
     * @return bool
     */
    public function validate(Booking $booking)
    {
        if (in_array($booking->getStatus(), Booking::$validatableStatus) && !$booking->isValidated()) {

            $event = new BookingValidateEvent($booking);
            $this->dispatcher->dispatch(BookingEvents::BOOKING_VALIDATE, $event);

            $booking = $event->getBooking();
            $validated = $event->getValidated();

            if ($validated) {
                $booking->setValidated(true);
                $booking = $this->save($booking);

                //Offerer nb bookings setting
                $offerer = $booking->getListing()->getUser();
                $offerer->setNbBookingsOfferer($offerer->getNbBookingsOfferer() + 1);
                $this->em->persist($offerer);
                $this->em->flush();

                //Asker nb bookings setting
                $asker = $booking->getUser();
                $asker->setNbBookingsAsker($asker->getNbBookingsAsker() + 1);
                $this->em->persist($asker);
                $this->em->flush();

                //Voucher used
                if ($this->voucherIsEnabled()) {
                    $this->voucherManager->checkVoucherUsed($booking);
                }

                //Mail offerer
                $this->mailer->sendReminderToRateAskerMessageToOfferer($booking);
                //Mail asker
                $this->mailer->sendReminderToRateOffererMessageToAsker($booking);

                return true;
            }
        }

        return false;
    }

    /**
     * Asker cancel booking.
     *  There are two cases:
     *      Either the booking has not been accepted by the offerer and so not already payed. Its status is new and
     *          no refund need to be made.
     *      Either booking status is payed and is not already validated. In this case the funds are in the asker wallet
     *      and must be refunded to his bank account.
     *
     *
     * Operations:
     *  Optionally refund asker
     *  Set booking status as cancel
     *  Send mails
     *
     * @param Booking $booking
     *
     * @return Booking|bool
     */
    public function cancel(Booking $booking)
    {
        if ($booking->canBeCanceledByAsker()) {
            $cancelable = false;

            if ($booking->getStatus() == Booking::STATUS_PAYED) {
                $event = new BookingPayinRefundEvent($booking);
                $this->dispatcher->dispatch(BookingEvents::BOOKING_REFUND, $event);

                $booking = $event->getBooking();
                $cancelable = $event->getCancelable();
            } elseif ($booking->getStatus() == Booking::STATUS_NEW) {
                $cancelable = true;
            }

            if ($cancelable) {
                if ($booking->getStatus() == Booking::STATUS_PAYED) {
                    //Free booking availabilities
                    $this->listingAvailabilityManager->saveAvailabilitiesStatus(
                        $booking->getListing()->getId(),
                        new DateRange($booking->getStart(), $booking->getEnd()),
                        array(),
                        $this->timeUnitIsDay ? array() : array(
                            new TimeRange($booking->getStartTime(), $booking->getEndTime())
                        ),
                        ListingAvailability::STATUS_AVAILABLE,
                        $booking->getListing()->getPrice(),
                        $this->endDayIncluded,
                        true
                    );
                }

                $booking->setStatus(Booking::STATUS_CANCELED_ASKER);
                $booking->setCanceledAskerBookingAt(new \DateTime());
                $booking = $this->save($booking);

                $this->mailer->sendBookingCanceledByAskerMessageToAsker($booking);
                $this->mailer->sendBookingCanceledByAskerMessageToOfferer($booking);
                $this->smser->sendBookingCanceledByAskerMessageToOfferer($booking);

                return $booking;
            }
        }

        return false;
    }

    /**
     * Accept or refuse booking from sms response
     *
     * @return bool|int
     */
    public function acceptOrRefuseFromSMS()
    {
        $result = 0;

        //Get all last sms response
        $start = new \DateTime();
        $interval = new \DateInterval('PT1H');
        $start->sub($interval);
        $end = new \DateTime();
        $end->add($interval);
        $allSMS = $this->smsReceiver->receiveAll($start, $end);

        //SMS response
        foreach ($allSMS as $sms) {
            //Get one sms response
            $smsReceived = $this->smsReceiver->receiveOne($sms->getId());
            if ($smsReceived) {
                //tag is of form: [SMS type]-[User Id]-[Booking Id]. See CoreBundle/TwigSmser->sendBookingMessagesToOfferer
                $tag = explode("-", $smsReceived->getTag());
                if (count($tag) == 3) {
                    $smsType = $tag[0];
                    $userId = $tag[1];
                    $bookingId = $tag[2];

                    if ($smsType == "booking_request_offerer" && $userId && $bookingId) {
                        /** @var Booking $booking */
                        $booking = $this->getRepository()
                            ->findOneBy(
                                array(
                                    'id' => $bookingId,
                                    'status' => Booking::STATUS_NEW
                                )
                            );

                        //If SMS received is send from offerer
                        if ($booking && $booking->getListing()->getUser()->getId() == $userId) {
                            $answer = $smsReceived->getMessage();
                            $answer = trim($answer);
                            if (strtolower($answer) == "yes" || strtolower($answer) == "oui") {
                                if ($this->pay($booking)) {
                                    $result++;
                                }
                            } elseif (strtolower($answer) == "no" || strtolower($answer) == "non") {
                                if ($this->refuse($booking)) {
                                    $result++;
                                }
                            }
                        }
                    }
                }
            }
        }

        //Check SMS credits left
        $smsCreditLeft = $this->smsReceiver->getProvider()->checkSMSCreditsLeft();
        $now = new \DateTime();

        if ($smsCreditLeft && $smsCreditLeft < 30 && $now->format('H:i') == '10:00') {
            $this->mailer->sendMessageToAdmin(
                'SMS credits limit reached',
                'Hello, The number of remaining SMS is ' . $smsCreditLeft . '.'
            );
        }

        return $result;
    }

    /**
     * Add listing options to the corresponding booking
     *
     * @param Booking $booking
     * @param array   $locales
     * @param string  $locale
     *
     * @return Booking
     */
    public function setBookingOptions(Booking $booking, $locales, $locale)
    {
        if ($this->optionIsEnabled()) {
            /** @var \Cocorico\ListingOptionBundle\Repository\ListingOptionRepository $repo */
            $repo = $this->getEntityManager()->getRepository('CocoricoListingOptionBundle:ListingOption');
            $listingOptions = $repo->findByListing($booking->getListing()->getId(), $locale);

            foreach ($listingOptions as $i => $listingOption) {
                $option = new \Cocorico\ListingOptionBundle\Entity\BookingOption();
                $option->setBooking($booking);
                $option->setPrice($listingOption->getPrice());
                $option->setMin($listingOption->getMin());
                $option->setMax($listingOption->getMax());
                $option->setType($listingOption->getType());
                $option->setListingOptionId($listingOption->getId());

                foreach ($locales as $locale) {
                    /** @var \Cocorico\ListingOptionBundle\Entity\ListingOptionTranslation $translation */
                    $translation = $listingOption->getTranslations()->get($locale);
                    $option
                        ->translate($locale)
                        ->setName($translation->getName())
                        ->setDescription($translation->getDescription());
                }

                $option->mergeNewTranslations();

                $booking->addOption($option);
            }
        }

        return $booking;
    }

    /**
     * @param  Booking $booking
     * @return Booking
     */
    public function save(Booking $booking)
    {
        $this->persistAndFlush($booking);

        return $booking;
    }

    /**
     * @return boolean
     */
    public function getTimeUnitIsDay()
    {
        return $this->timeUnitIsDay;
    }

    /**
     * @return TwigSwiftMailer
     */
    public function getMailer()
    {
        return $this->mailer;
    }

    //todo: use kernel.bundles param instead xxxIsEnabled methods
    /**
     * @return bool
     */
    public function mangopayIsEnabled()
    {
        return $this->em->getClassMetadata('Cocorico\CoreBundle\Entity\Booking')->hasField('mangopayPayinPreAuthId');
    }

    /**
     * @return bool
     * @throws \Exception
     */
    public function voucherIsEnabled()
    {
        $voucherIsEnabled = !$this->em->getMetadataFactory()->isTransient('Cocorico\VoucherBundle\Entity\Voucher');
        //Voucher and Option Bundles not ready yet for booking amount computing
        if ($voucherIsEnabled && $this->optionIsEnabled()) {
            throw new \Exception("Voucher and Option are enabled but not ready yet");
        }

        return $voucherIsEnabled;
    }

    /**
     * @return bool
     */
    public function optionIsEnabled()
    {
        return !$this->em->getMetadataFactory()->isTransient('Cocorico\ListingOptionBundle\Entity\ListingOption');
    }

    /**
     * @return bool
     */
    public function deliveryIsEnabled()
    {
        return $this->em->getClassMetadata('Cocorico\CoreBundle\Entity\Booking')->hasField('amountDelivery');
    }

    /**
     *
     * @return BookingRepository
     */
    public function getRepository()
    {
        return $this->em->getRepository('CocoricoCoreBundle:Booking');
    }

    /**
     *
     * @return EntityManager
     */
    public function getEntityManager()
    {
        return $this->em;
    }
}

redpajama_set_name: RedPajamaGithub


text:
"""Test configuration for the ZHA component."""
from unittest.mock import patch
import pytest
from homeassistant import config_entries
from homeassistant.components.zha.core.const import DOMAIN, DATA_ZHA, COMPONENTS
from homeassistant.helpers.device_registry import async_get_registry as get_dev_reg
from homeassistant.components.zha.core.gateway import ZHAGateway
from homeassistant.components.zha.core.registries import establish_device_mappings
from .common import async_setup_entry
from homeassistant.components.zha.core.store import async_get_registry

@pytest.fixture(name="config_entry")
def config_entry_fixture(hass):
    """Fixture representing a config entry."""
    config_entry = config_entries.ConfigEntry(
        1, DOMAIN, "Mock Title", {}, "test", config_entries.CONN_CLASS_LOCAL_PUSH
    )
    return config_entry

@pytest.fixture(name="zha_gateway")
async def zha_gateway_fixture(hass, config_entry):
    """Fixture representing a zha gateway.

    Create a ZHAGateway object that can be used to interact with as if we
    had a real zigbee network running.
    """
    establish_device_mappings()
    for component in COMPONENTS:
        hass.data[DATA_ZHA][component] = hass.data[DATA_ZHA].get(component, {})
    zha_storage = await async_get_registry(hass)
    dev_reg = await get_dev_reg(hass)
    gateway = ZHAGateway(hass, {}, config_entry)
    gateway.zha_storage = zha_storage
    gateway.ha_device_registry = dev_reg
    return gateway

@pytest.fixture(autouse=True)
async def setup_zha(hass, config_entry):
    """Load the ZHA component.

    This will init the ZHA component. It loads the component in HA so that
    we can test the domains that ZHA supports without actually having a zigbee
    network running.
    """
    # this prevents needing an actual radio and zigbee network available
    with patch("homeassistant.components.zha.async_setup_entry", async_setup_entry):
        hass.data[DATA_ZHA] = {}

        # init ZHA
        await hass.config_entries.async_forward_entry_setup(config_entry, DOMAIN)
        await hass.async_block_till_done()


text:
package errorutil

import (
	"errors"
	"testing"
)

func returnsError() error {
	return errors.New("test")
}
func TestIgnoreHandler(t *testing.T) {
	defer func() {
		if r := recover(); r != nil {
			t.Fatal("IgnoreHandler did not ignore Error")
		}
	}()

	Ignore(returnsError)

}


text:
$import("com.ctrip.tars.base.Service");
$import("com.ctrip.tars.util.Fridge");

Class.forName({
  name: "class com.ctrip.tars.base.PaginationService extends com.ctrip.tars.base.Service",

  PaginationService: function() {},

  "public static final SCOUR": -1,
  "public static final REPLACE": 0,
  "public static final INSERT": 1,
  "public static final APPEND": 2,

  "@Setter @Getter private pageSize": PAGE_SIZE,

  "private data": {
    count: 0,
    next: null,
    pageCount: 0,
    data: new com.ctrip.tars.util.Fridge()
  },

  count: function() {
    return this.data.count;
  },

  size: function() {
    return this.data.data.length;
  },

  getData: function() {
    return this.data.data;
  },

  clear: function() {
    this.data.count = 0;
    this.data.next = null;
    this.data.pageCount = 0;
    this.data.data.clear();
    this.update();
  },

  "protected parse": function(data, params, mode) {
    var results = data.results || [];

    switch (mode) {
      case com.ctrip.tars.base.PaginationService.REPLACE:
        this.data.data.replace(results, "id");
        break;
      case com.ctrip.tars.base.PaginationService.SCOUR:
        this.data.data.scour(results, "id");
        break;
      case com.ctrip.tars.base.PaginationService.INSERT:
        this.data.data.insert(results);
        break;
      case com.ctrip.tars.base.PaginationService.APPEND:
      default:
        this.data.data.append(results);
        break;
    }

    this.data.count = data.count;
    this.data.next = data.next;
  },

  first: function(path, filters, sorters, callback) {
    this.clear();
    this.loadData(this.getUrl(path), filters, sorters, {
      page_size: this.pageSize,
      page: 1
    }, function() {
      this.update(callback);
    }, com.ctrip.tars.base.PaginationService.REPLACE);
  },

  refresh: function(path, filters, sorters, callback) {
    this.loadData(this.getUrl(path), filters, sorters, {
      page_size: Math.max(this.size(), this.pageSize),
      page: 1
    }, function() {
      this.update(callback);
    }, com.ctrip.tars.base.PaginationService.SCOUR);
  },

  next: function(callback) {
    this.loadData(this.data.next, null, null, null, function() {
      this.update(callback);
    }, com.ctrip.tars.base.PaginationService.APPEND);
  },

  filterData: function(map, callback) {
    var data = [];
    for (var i = 0, len = this.data.data.length; i < len; i++) {
      var obj = this.data.data[i];

      if (obj) {
        for (var key in map) {
          var value = map[key];

          if (obj[key] !== value) {
            obj = null;
            break;
          }
        }
      }

      if (obj) {
        data.push(obj);
        if (!Object.isNull(callback) && Object.isFunction(callback)) {
          callback(i, obj, this.data.data);
        }
      }
    }
    return data;
  }
});


text:
'use strict';

var _ = require('lodash');

function DisplayBase(eventBus) {
    this._eventBus = eventBus;

    eventBus.on('off', function () {
        this.clear();
    }.bind(this));
}

DisplayBase.$inject = [ 'eventBus' ];

module.exports = DisplayBase;

DisplayBase.prototype.init = function (name, size) {
    this.name = name;
    this.size = size;

    this.characters = [];
    for (var i=0; i < size; i++) {
        this.characters.push({
            text: '',
            cursor: false,
            blinking: false
        });
    }
};

DisplayBase.prototype.getCursor = function() {
    return _.findIndex(this.characters, function (c) {
        return c.cursor;
    });
};

DisplayBase.prototype.getBlinking = function() {
    return _.findIndex(this.characters, function (c) {
        return c.blinking;
    });
};

DisplayBase.prototype.setBlinking = function (position) {
    if (position === false) {
        _.forEach(this.characters, function (c, i) {
            c.blinking = false;
        });
    }
    else if (_.isArray(position)) {
        _.forEach(this.characters, function (c, i) {
            c.blinking = position.indexOf(i) !== -1;
        });
    }
    else {
        var blinking = this.getBlinking();
        if (blinking === position) {
            return;
        }

        if (blinking >= 0) {
            this.characters[blinking].blinking = false;
        }

        if (position >= 0) {
            this.characters[position].blinking = true;
        }
    }

    this._fireChanged();
};

DisplayBase.prototype.noBlinking = function () {
    this.setBlinking(-1);
};

DisplayBase.prototype.setCursor = function (position) {
    if (position === false) {
        _.forEach(this.characters, function (c, i) {
            c.cursor = false;
        });
    }
    else {
        var cursor = this.getCursor();
        if (cursor === position) {
            return;
        }

        if (cursor >= 0) {
            this.characters[cursor].cursor = false;
        }

        if (position >= 0) {
            this.characters[position].cursor = true;
        }
    }

    this._fireChanged();
};

DisplayBase.prototype.noCursor = function () {
    this.setCursor(-1);
};

DisplayBase.prototype.setText = function (text, options) {
    if (text.length > this.size) {
        text = text.substring(0, text.length);
    }
    else if (text.length < this.size && options && options.center) {
        text = _.pad(text, this.size);
    }

    if (this.text == text) {
        return;
    }

    _.forEach(this.characters, function (c, i) {
        c.text = text.length > i ? text[i] : '';
    });

    this.text = text;
    this._fireChanged();
};

DisplayBase.prototype.getText = function () {
    return this.text;
};

DisplayBase.prototype.toString = function () {
    var text = '';
    _.forEach(this.characters, function (c, i) {
        text += (!c.text ? ' ' : c.text);
    });

    return text;
};

DisplayBase.prototype.clear = function () {
    this.setText('');
    this.noCursor();
    this.noBlinking();
};

DisplayBase.prototype._fireChanged = function () {
    this._eventBus.fire(this.name+'.changed', { display: this });
};

DisplayBase.prototype.get = DisplayBase.prototype.getText;
DisplayBase.prototype.set = DisplayBase.prototype.setText;


text:
using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;

namespace Geocoding.MapQuest
{
	/// <summary>
	/// Result obj returned in a collection of OSM response under the property: results
	/// </summary>
	public class MapQuestResult
	{
		[JsonProperty("locations")]
		public IList<MapQuestLocation> Locations { get; set; }

		[JsonProperty("providedLocation")]
		public MapQuestLocation ProvidedLocation { get; set; }
	}
}


text:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<resources>
  <resource name="oControl" type="RESOURCE"/>
  <resource name="oBullet" type="RESOURCE"/>
  <resource name="oEnemy" type="RESOURCE"/>
</resources>


text:
namespace content {

SurfaceDisplayOutputSurface::SurfaceDisplayOutputSurface(
    cc::SurfaceManager* surface_manager,
    uint32_t surface_id_namespace,
    const scoped_refptr<cc::ContextProvider>& context_provider)
    : cc::OutputSurface(context_provider,
                        scoped_ptr<cc::SoftwareOutputDevice>()),
      display_(NULL),
      surface_manager_(surface_manager),
      factory_(surface_manager, this),
      allocator_(surface_id_namespace) {
  capabilities_.delegated_rendering = true;
  capabilities_.max_frames_pending = 1;
}

SurfaceDisplayOutputSurface::~SurfaceDisplayOutputSurface() {
  client_ = NULL;
  if (!surface_id_.is_null()) {
    factory_.Destroy(surface_id_);
  }
}

void SurfaceDisplayOutputSurface::SwapBuffers(cc::CompositorFrame* frame) {
  gfx::Size frame_size =
      frame->delegated_frame_data->render_pass_list.back()->output_rect.size();
  if (frame_size != display_size_) {
    if (!surface_id_.is_null()) {
      factory_.Destroy(surface_id_);
    }
    surface_id_ = allocator_.GenerateId();
    factory_.Create(surface_id_, frame_size);
    display_size_ = frame_size;
    display_->Resize(surface_id_, frame_size);
  }

  scoped_ptr<cc::CompositorFrame> frame_copy(new cc::CompositorFrame());
  frame->AssignTo(frame_copy.get());
  factory_.SubmitFrame(surface_id_, frame_copy.Pass());

  client_->DidSwapBuffers();
  client_->DidSwapBuffersComplete();
}

void SurfaceDisplayOutputSurface::ReturnResources(
    const cc::ReturnedResourceArray& resources) {
  cc::CompositorFrameAck ack;
  ack.resources = resources;
  if (client_)
    client_->ReclaimResources(&ack);
}

}  // namespace content


text:
source $DOTFILES/init/npm.sh

# Install Ruby Gems
source $DOTFILES/init/gem.sh


text:
<?php
namespace Infrastructure\Middleware;

use Slim\Http\Request;
use Slim\Http\Response;

class CsrfViewMiddleware extends Middleware
{
    private const INDEX_NAME = 'csrf';

    protected $tokenName;
    protected $tokenNameKey;
    protected $tokenValue;
    protected $tokenValueKey;

    public function __invoke(Request $request, Response $response, $next)
    {
        $this->tokenName = $this->container->get('csrf')->getTokenName();
        $this->tokenNameKey = $this->container->get('csrf')->getTokenNameKey();
        $this->tokenValue = $this->container->get('csrf')->getTokenValue();
        $this->tokenValueKey = $this->container->get('csrf')->getTokenValueKey();

        $this->container->get('view')->getEnvironment()->addGlobal(self::INDEX_NAME, $this->generateInputFields());

        return $next($request, $response);
    }

    public function generateInputFields()
    {
        return '
            <input type="hidden" name="' . $this->tokenNameKey . '" value="' . $this->tokenName . '">
            <input type="hidden" name="' . $this->tokenValueKey . '" value="' . $this->tokenValue . '">
        ';
    }
}


text:
@interface AssetsLib ()

@property (nonatomic, strong) ALAssetsLibrary *assetsLibrary;
@property (nonatomic, strong) NSMutableArray *groups;
@property (nonatomic, strong) NSMutableArray *assets;
@property (nonatomic, strong) NSDateFormatter *dateFormatter;
@property int assetsCount;

@end

@implementation AssetsLib

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// getAllPhotoThumbnails

- (void)getAllPhotos:(CDVInvokedUrlCommand*)command
{
    NSLog(@"getAllPhotos");
    if (self.assetsLibrary == nil) {
        _assetsLibrary = [[ALAssetsLibrary alloc] init];
    }
    if (self.groups == nil) {
        _groups = [[NSMutableArray alloc] init];
    } else {
        [self.groups removeAllObjects];
    }
    if (!self.assets) {
        _assets = [[NSMutableArray alloc] init];
    } else {
        [self.assets removeAllObjects];
    }
    self.assetsCount = 0;

    ALAssetsGroupEnumerationResultsBlock assetsEnumerationBlock = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
        if (result) {
            [self.assets addObject:result];
            if ([self.assets count] == self.assetsCount)
            {
                NSLog(@"Got all %d photos",self.assetsCount);
                [self getAllPhotosComplete:command with:nil];
            }
        }
    };

    // setup our failure view controller in case enumerateGroupsWithTypes fails
    ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError *error) {

        NSString* errorMessage = nil;
        switch ([error code]) {
            case ALAssetsLibraryAccessUserDeniedError:
            case ALAssetsLibraryAccessGloballyDeniedError:
                errorMessage = @"The user has declined access to it.";
                break;
            default:
                errorMessage = @"Reason unknown.";
                break;
        }
        NSLog(@"Problem reading assets library %@",errorMessage);
        [self getAllPhotosComplete:command with:errorMessage];
    };

    ALAssetsLibraryGroupsEnumerationResultsBlock listGroupBlock = ^(ALAssetsGroup *group, BOOL *stop) {
        ALAssetsFilter *onlyPhotosFilter = [ALAssetsFilter allPhotos];
        [group setAssetsFilter:onlyPhotosFilter];
        // NSLog(@"AssetsLib::getAllPhotos::listGroupBlock > %@ (%d)   type: %@    url: %@",[group valueForProperty:ALAssetsGroupPropertyName],[group numberOfAssets],[group valueForProperty:ALAssetsGroupPropertyType],[group valueForProperty:ALAssetsGroupPropertyURL]);
        if ([group numberOfAssets] > 0)
        {
            NSLog(@"Got asset group \"%@\" with %ld photos",[group valueForProperty:ALAssetsGroupPropertyName],(long)[group numberOfAssets]);
            [self.groups addObject:group];
            self.assetsCount += [group numberOfAssets];
        }
        else
        {
            NSLog(@"Got all %lu asset groups with total %d assets",(unsigned long)[self.groups count],self.assetsCount);
            for (group in self.groups)
            {   // Enumarate each asset group
                ALAssetsFilter *onlyPhotosFilter = [ALAssetsFilter allPhotos];
                [group setAssetsFilter:onlyPhotosFilter];
                [group enumerateAssetsUsingBlock:assetsEnumerationBlock];
            }
        }
    };

    // enumerate only photos
    NSUInteger groupTypes = ALAssetsGroupAll; // ALAssetsGroupAlbum | ALAssetsGroupEvent | ALAssetsGroupFaces | ALAssetsGroupSavedPhotos | ALAssetsGroupPhotoStream;
    [self.assetsLibrary enumerateGroupsWithTypes:groupTypes usingBlock:listGroupBlock failureBlock:failureBlock];
}

- (void)getAllPhotosComplete:(CDVInvokedUrlCommand*)command with:(NSString*)error
{
    CDVPluginResult* pluginResult = nil;

    if (error != nil && [error length] > 0)
    {   // Call error
        NSLog(@"Error occured for command.callbackId:%@, error:%@", command.callbackId, error);
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:error];
    }
    else
    {   // Call was successful
        NSMutableDictionary* photos = [NSMutableDictionary dictionaryWithDictionary:@{}];
        for (int i=0; i<[self.assets count]; i++)
        {
            ALAsset* asset = self.assets[i];
            NSString* url = [[asset valueForProperty:ALAssetPropertyAssetURL] absoluteString];
            NSDictionary* photo = @{
                                    @"url": url
                                   };
            [photos setObject:photo forKey:photo[@"url"]];
        }
        NSArray* photoMsg = [photos allValues];
        NSLog(@"Sending to phonegap application message with %lu photos",(unsigned long)[photoMsg count]);
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:photoMsg];
    }

    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// getPhotoMetadata

- (void)getPhotoMetadata:(CDVInvokedUrlCommand*)command
{
    NSLog(@"getPhotoMetadata");

    ALAssetsLibraryProcessBlock processMetadataBlock = ^(ALAsset *asset) {
        if (self.dateFormatter == nil) {
            _dateFormatter = [[NSDateFormatter alloc] init];
            _dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
        }
        NSString* url = [[asset valueForProperty:ALAssetPropertyAssetURL] absoluteString];
        NSString* date = [self.dateFormatter stringFromDate:[asset valueForProperty:ALAssetPropertyDate]];

        NSDictionary* photo = @{
                                @"url": url,
                                @"date": date
                               };
        NSMutableDictionary* photometa = [self getImageMeta:asset];
        [photometa addEntriesFromDictionary:photo];
        return photometa;
    };

    [self getPhotos:command processBlock:processMetadataBlock];
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// getThumbnails

- (void)getThumbnails:(CDVInvokedUrlCommand*)command
{
    NSLog(@"getThumbnails");

    ALAssetsLibraryProcessBlock processThumbnailsBlock = ^(ALAsset *asset) {
        NSString* url = [[asset valueForProperty:ALAssetPropertyAssetURL] absoluteString];
        CGImageRef thumbnailImageRef = [asset thumbnail];
        UIImage* thumbnail = [UIImage imageWithCGImage:thumbnailImageRef];
        NSString* base64encoded = [UIImagePNGRepresentation(thumbnail) base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
        NSDictionary* photo = @{
                                @"url": url,
                                @"base64encoded": base64encoded
                               };
        return photo;
    };

    [self.commandDelegate runInBackground:^{
        [self getPhotos:command processBlock:processThumbnailsBlock];
    }];
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Gets asset representation meta data
- (NSMutableDictionary* ) getImageMeta:(ALAsset*)asset
{
    ALAssetRepresentation* representation = [asset defaultRepresentation];
    struct CGSize size = [representation dimensions];
    NSDictionary* metadata = [representation metadata];

    NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
    [dict setValue:[representation filename] forKey:@"filename"];
    [dict setValue:@(size.width) forKey:@"width"];
    [dict setValue:@(size.height) forKey:@"height"];

    //@"{GPS}"
    NSDictionary* gps = [metadata objectForKey:@"{GPS}"];
    if (gps != nil){
        NSNumber* Latitude     = [gps objectForKey:@"Latitude"];
        NSNumber* Longitude    = [gps objectForKey:@"Longitude"];
        NSString* LatitudeRef  = [gps objectForKey:@"LatitudeRef"];
        NSString* LongitudeRef = [gps objectForKey:@"LongitudeRef"];
        [dict setValue:Latitude forKey:@"gps_Latitude"];
        [dict setValue:Longitude forKey:@"gps_Longitude"];
        [dict setValue:LatitudeRef forKey:@"gps_LatitudeRef"];
        [dict setValue:LongitudeRef forKey:@"gps_LongitudeRef"];
    }
    //@"{Exif}"
    NSDictionary* exif = [metadata objectForKey:@"{Exif}"];
    if (exif != nil){
        NSString* DateTimeOriginal  = [exif objectForKey:@"DateTimeOriginal"];
        NSString* DateTimeDigitized = [exif objectForKey:@"DateTimeDigitized"];
        [dict setValue:DateTimeOriginal forKey:@"exif_DateTimeOriginal"];
        [dict setValue:DateTimeDigitized forKey:@"exif_DateTimeDigitized"];
    }
    //@"{IPTC}"
    NSDictionary* iptc = [metadata objectForKey:@"{IPTC}"];
    if (iptc != nil){
        NSArray* Keywords = [iptc objectForKey:@"Keywords"];
        [dict setValue:Keywords forKey:@"iptc_Keywords"];
    }
    //[AssetsLib logDict:dict];
    return dict;
}

+ (void) logDict:(NSDictionary*)dict
{
    for (id key in dict)
    {
        NSLog(@"key: %@, value: %@ ", key, [dict objectForKey:key]);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Common method which gets assets for one or more url's and processes them given processBlock

// This block is executed for each asset
typedef NSDictionary* (^ALAssetsLibraryProcessBlock)(ALAsset *asset);

- (void)getPhotos:(CDVInvokedUrlCommand*)command processBlock:(ALAssetsLibraryProcessBlock)process
{
    NSArray* urlList = [command.arguments objectAtIndex:0];
    if (urlList != nil && [urlList count] > 0)
    {
        if (self.assetsLibrary == nil) {
            _assetsLibrary = [[ALAssetsLibrary alloc] init];
        }

        NSMutableDictionary* photos = [NSMutableDictionary dictionaryWithDictionary:@{}];

        for (int i=0; i<[urlList count]; i++)
        {
            NSString* urlString = [urlList objectAtIndex:i];
            NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
            //NSLog(@"Asset url: %@", url);
            [self.assetsLibrary assetForURL:url
                                resultBlock: ^(ALAsset *asset){
                                    NSDictionary* photo = process(asset);
                                    NSLog(@"Done %d: %@", i, photo[@"url"]);
                                    [photos setObject:photo forKey:photo[@"url"]];
                                    if ([urlList count] == [photos count])
                                    {
                                        NSArray* photoMsg = [photos allValues];
                                        NSLog(@"Sending to phonegap application message with %lu photos",(unsigned long)[photoMsg count]);
                                        CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:photoMsg];
                                        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
                                    }
                                }
                               failureBlock: ^(NSError *error)
             {
                 NSLog(@"Failed to process asset(s)");
                 [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR] callbackId:command.callbackId];
             }
             ];
        }
    }
    else
    {
        NSLog(@"Missing parameter urlList");
        [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR] callbackId:command.callbackId];
    }
}

@end


text:
<?php

namespace Drupal\FunctionalTests\Hal;

use Drupal\FunctionalTests\Rest\EntityViewModeResourceTestBase;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;

/**
 * @group hal
 */
class EntityViewModeHalJsonBasicAuthTest extends EntityViewModeResourceTestBase {

  use BasicAuthResourceTestTrait;

  /**
   * {@inheritdoc}
   */
  public static $modules = ['hal', 'basic_auth'];

  /**
   * {@inheritdoc}
   */
  protected static $format = 'hal_json';

  /**
   * {@inheritdoc}
   */
  protected static $mimeType = 'application/hal+json';

  /**
   * {@inheritdoc}
   */
  protected static $auth = 'basic_auth';

}