text:
import { localize } from 'vs/nls';

import * as Objects from 'vs/base/common/objects';
import * as Strings from 'vs/base/common/strings';
import * as Assert from 'vs/base/common/assert';
import { join } from 'vs/base/common/path';
import * as Types from 'vs/base/common/types';
import * as UUID from 'vs/base/common/uuid';
import * as Platform from 'vs/base/common/platform';
import Severity from 'vs/base/common/severity';
import { URI } from 'vs/base/common/uri';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { ValidationStatus, ValidationState, IProblemReporter, Parser } from 'vs/base/common/parsers';
import { IStringDictionary } from 'vs/base/common/collections';

import { IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers';
import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { Event, Emitter } from 'vs/base/common/event';
import { IFileService, IFileStat } from 'vs/platform/files/common/files';

export enum FileLocationKind {
	Default,
	Relative,
	Absolute,
	AutoDetect
}

export module FileLocationKind {
	export function fromString(value: string): FileLocationKind | undefined {
		value = value.toLowerCase();
		if (value === 'absolute') {
			return FileLocationKind.Absolute;
		} else if (value === 'relative') {
			return FileLocationKind.Relative;
		} else if (value === 'autodetect') {
			return FileLocationKind.AutoDetect;
		} else {
			return undefined;
		}
	}
}

export enum ProblemLocationKind {
	File,
	Location
}

export module ProblemLocationKind {
	export function fromString(value: string): ProblemLocationKind | undefined {
		value = value.toLowerCase();
		if (value === 'file') {
			return ProblemLocationKind.File;
		} else if (value === 'location') {
			return ProblemLocationKind.Location;
		} else {
			return undefined;
		}
	}
}

export interface ProblemPattern {
	regexp: RegExp;

	kind?: ProblemLocationKind;

	file?: number;

	message?: number;

	location?: number;

	line?: number;

	character?: number;

	endLine?: number;

	endCharacter?: number;

	code?: number;

	severity?: number;

	loop?: boolean;
}

export interface NamedProblemPattern extends ProblemPattern {
	name: string;
}

export type MultiLineProblemPattern = ProblemPattern[];

export interface WatchingPattern {
	regexp: RegExp;
	file?: number;
}

export interface WatchingMatcher {
	activeOnStart: boolean;
	beginsPattern: WatchingPattern;
	endsPattern: WatchingPattern;
}

export enum ApplyToKind {
	allDocuments,
	openDocuments,
	closedDocuments
}

export module ApplyToKind {
	export function fromString(value: string): ApplyToKind | undefined {
		value = value.toLowerCase();
		if (value === 'alldocuments') {
			return ApplyToKind.allDocuments;
		} else if (value === 'opendocuments') {
			return ApplyToKind.openDocuments;
		} else if (value === 'closeddocuments') {
			return ApplyToKind.closedDocuments;
		} else {
			return undefined;
		}
	}
}

export interface ProblemMatcher {
	owner: string;
	source?: string;
	applyTo: ApplyToKind;
	fileLocation: FileLocationKind;
	filePrefix?: string;
	pattern: ProblemPattern | ProblemPattern[];
	severity?: Severity;
	watching?: WatchingMatcher;
	uriProvider?: (path: string) => URI;
}

export interface NamedProblemMatcher extends ProblemMatcher {
	name: string;
	label: string;
	deprecated?: boolean;
}

export interface NamedMultiLineProblemPattern {
	name: string;
	label: string;
	patterns: MultiLineProblemPattern;
}

export function isNamedProblemMatcher(value: ProblemMatcher | undefined): value is NamedProblemMatcher {
	return value && Types.isString((<NamedProblemMatcher>value).name) ? true : false;
}

interface Location {
	startLineNumber: number;
	startCharacter: number;
	endLineNumber: number;
	endCharacter: number;
}

interface ProblemData {
	kind?: ProblemLocationKind;
	file?: string;
	location?: string;
	line?: string;
	character?: string;
	endLine?: string;
	endCharacter?: string;
	message?: string;
	severity?: string;
	code?: string;
}

export interface ProblemMatch {
	resource: Promise<URI>;
	marker: IMarkerData;
	description: ProblemMatcher;
}

export interface HandleResult {
	match: ProblemMatch | null;
	continue: boolean;
}

export async function getResource(filename: string, matcher: ProblemMatcher, fileService?: IFileService): Promise<URI> {
	let kind = matcher.fileLocation;
	let fullPath: string | undefined;
	if (kind === FileLocationKind.Absolute) {
		fullPath = filename;
	} else if ((kind === FileLocationKind.Relative) && matcher.filePrefix) {
		fullPath = join(matcher.filePrefix, filename);
	} else if (kind === FileLocationKind.AutoDetect) {
		const matcherClone = Objects.deepClone(matcher);
		matcherClone.fileLocation = FileLocationKind.Relative;
		if (fileService) {
			const relative = await getResource(filename, matcherClone);
			let stat: IFileStat | undefined = undefined;
			try {
				stat = await fileService.resolve(relative);
			} catch (ex) {
				// Do nothing, we just need to catch file resolution errors.
			}
			if (stat) {
				return relative;
			}
		}

		matcherClone.fileLocation = FileLocationKind.Absolute;
		return getResource(filename, matcherClone);
	}
	if (fullPath === undefined) {
		throw new Error('FileLocationKind is not actionable. Does the matcher have a filePrefix? This should never happen.');
	}
	fullPath = fullPath.replace(/\\/g, '/');
	if (fullPath[0] !== '/') {
		fullPath = '/' + fullPath;
	}
	if (matcher.uriProvider !== undefined) {
		return matcher.uriProvider(fullPath);
	} else {
		return URI.file(fullPath);
	}
}

export interface ILineMatcher {
	matchLength: number;
	next(line: string): ProblemMatch | null;
	handle(lines: string[], start?: number): HandleResult;
}

export function createLineMatcher(matcher: ProblemMatcher, fileService?: IFileService): ILineMatcher {
	let pattern = matcher.pattern;
	if (Types.isArray(pattern)) {
		return new MultiLineMatcher(matcher, fileService);
	} else {
		return new SingleLineMatcher(matcher, fileService);
	}
}

const endOfLine: string = Platform.OS === Platform.OperatingSystem.Windows ? '\r\n' : '\n';

abstract class AbstractLineMatcher implements ILineMatcher {
	private matcher: ProblemMatcher;
	private fileService?: IFileService;

	constructor(matcher: ProblemMatcher, fileService?: IFileService) {
		this.matcher = matcher;
		this.fileService = fileService;
	}

	public handle(lines: string[], start: number = 0): HandleResult {
		return { match: null, continue: false };
	}

	public next(line: string): ProblemMatch | null {
		return null;
	}

	public abstract get matchLength(): number;

	protected fillProblemData(data: ProblemData | null, pattern: ProblemPattern, matches: RegExpExecArray): data is ProblemData {
		if (data) {
			this.fillProperty(data, 'file', pattern, matches, true);
			this.appendProperty(data, 'message', pattern, matches, true);
			this.fillProperty(data, 'code', pattern, matches, true);
			this.fillProperty(data, 'severity', pattern, matches, true);
			this.fillProperty(data, 'location', pattern, matches, true);
			this.fillProperty(data, 'line', pattern, matches);
			this.fillProperty(data, 'character', pattern, matches);
			this.fillProperty(data, 'endLine', pattern, matches);
			this.fillProperty(data, 'endCharacter', pattern, matches);
			return true;
		} else {
			return false;
		}
	}

	private appendProperty(data: ProblemData, property: keyof ProblemData, pattern: ProblemPattern, matches: RegExpExecArray, trim: boolean = false): void {
		const patternProperty = pattern[property];
		if (Types.isUndefined(data[property])) {
			this.fillProperty(data, property, pattern, matches, trim);
		}
		else if (!Types.isUndefined(patternProperty) && patternProperty < matches.length) {
			let value = matches[patternProperty];
			if (trim) {
				value = Strings.trim(value)!;
			}
			(data as any)[property] += endOfLine + value;
		}
	}

	private fillProperty(data: ProblemData, property: keyof ProblemData, pattern: ProblemPattern, matches: RegExpExecArray, trim: boolean = false): void {
		const patternAtProperty = pattern[property];
		if (Types.isUndefined(data[property]) && !Types.isUndefined(patternAtProperty) && patternAtProperty < matches.length) {
			let value = matches[patternAtProperty];
			if (value !== undefined) {
				if (trim) {
					value = Strings.trim(value)!;
				}
				(data as any)[property] = value;
			}
		}
	}

	protected getMarkerMatch(data: ProblemData): ProblemMatch | undefined {
		try {
			let location = this.getLocation(data);
			if (data.file && location && data.message) {
				let marker: IMarkerData = {
					severity: this.getSeverity(data),
					startLineNumber: location.startLineNumber,
					startColumn: location.startCharacter,
					endLineNumber: location.endLineNumber,
					endColumn: location.endCharacter,
					message: data.message
				};
				if (data.code !== undefined) {
					marker.code = data.code;
				}
				if (this.matcher.source !== undefined) {
					marker.source = this.matcher.source;
				}
				return {
					description: this.matcher,
					resource: this.getResource(data.file),
					marker: marker
				};
			}
		} catch (err) {
			console.error(`Failed to convert problem data into match: ${JSON.stringify(data)}`);
		}
		return undefined;
	}

	protected getResource(filename: string): Promise<URI> {
		return getResource(filename, this.matcher, this.fileService);
	}

	private getLocation(data: ProblemData): Location | null {
		if (data.kind === ProblemLocationKind.File) {
			return this.createLocation(0, 0, 0, 0);
		}
		if (data.location) {
			return this.parseLocationInfo(data.location);
		}
		if (!data.line) {
			return null;
		}
		let startLine = parseInt(data.line);
		let startColumn = data.character ? parseInt(data.character) : undefined;
		let endLine = data.endLine ? parseInt(data.endLine) : undefined;
		let endColumn = data.endCharacter ? parseInt(data.endCharacter) : undefined;
		return this.createLocation(startLine, startColumn, endLine, endColumn);
	}

	private parseLocationInfo(value: string): Location | null {
		if (!value || !value.match(/(\d+|\d+,\d+|\d+,\d+,\d+,\d+)/)) {
			return null;
		}
		let parts = value.split(',');
		let startLine = parseInt(parts[0]);
		let startColumn = parts.length > 1 ? parseInt(parts[1]) : undefined;
		if (parts.length > 3) {
			return this.createLocation(startLine, startColumn, parseInt(parts[2]), parseInt(parts[3]));
		} else {
			return this.createLocation(startLine, startColumn, undefined, undefined);
		}
	}

	private createLocation(startLine: number, startColumn: number | undefined, endLine: number | undefined, endColumn: number | undefined): Location {
		if (startColumn !== undefined && endColumn !== undefined) {
			return { startLineNumber: startLine, startCharacter: startColumn, endLineNumber: endLine || startLine, endCharacter: endColumn };
		}
		if (startColumn !== undefined) {
			return { startLineNumber: startLine, startCharacter: startColumn, endLineNumber: startLine, endCharacter: startColumn };
		}
		return { startLineNumber: startLine, startCharacter: 1, endLineNumber: startLine, endCharacter: Number.MAX_VALUE };
	}

	private getSeverity(data: ProblemData): MarkerSeverity {
		let result: Severity | null = null;
		if (data.severity) {
			let value = data.severity;
			if (value) {
				result = Severity.fromValue(value);
				if (result === Severity.Ignore) {
					if (value === 'E') {
						result = Severity.Error;
					} else if (value === 'W') {
						result = Severity.Warning;
					} else if (value === 'I') {
						result = Severity.Info;
					} else if (Strings.equalsIgnoreCase(value, 'hint')) {
						result = Severity.Info;
					} else if (Strings.equalsIgnoreCase(value, 'note')) {
						result = Severity.Info;
					}
				}
			}
		}
		if (result === null || result === Severity.Ignore) {
			result = this.matcher.severity || Severity.Error;
		}
		return MarkerSeverity.fromSeverity(result);
	}
}

class SingleLineMatcher extends AbstractLineMatcher {

	private pattern: ProblemPattern;

	constructor(matcher: ProblemMatcher, fileService?: IFileService) {
		super(matcher, fileService);
		this.pattern = <ProblemPattern>matcher.pattern;
	}

	public get matchLength(): number {
		return 1;
	}

	public handle(lines: string[], start: number = 0): HandleResult {
		Assert.ok(lines.length - start === 1);
		let data: ProblemData = Object.create(null);
		if (this.pattern.kind !== undefined) {
			data.kind = this.pattern.kind;
		}
		let matches = this.pattern.regexp.exec(lines[start]);
		if (matches) {
			this.fillProblemData(data, this.pattern, matches);
			let match = this.getMarkerMatch(data);
			if (match) {
				return { match: match, continue: false };
			}
		}
		return { match: null, continue: false };
	}

	public next(line: string): ProblemMatch | null {
		return null;
	}
}

class MultiLineMatcher extends AbstractLineMatcher {

	private patterns: ProblemPattern[];
	private data: ProblemData | null;

	constructor(matcher: ProblemMatcher, fileService?: IFileService) {
		super(matcher, fileService);
		this.patterns = <ProblemPattern[]>matcher.pattern;
	}

	public get matchLength(): number {
		return this.patterns.length;
	}

	public handle(lines: string[], start: number = 0): HandleResult {
		Assert.ok(lines.length - start === this.patterns.length);
		this.data = Object.create(null);
		let data = this.data!;
		data.kind = this.patterns[0].kind;
		for (let i = 0; i < this.patterns.length; i++) {
			let pattern = this.patterns[i];
			let matches = pattern.regexp.exec(lines[i + start]);
			if (!matches) {
				return { match: null, continue: false };
			} else {
				// Only the last pattern can loop
				if (pattern.loop && i === this.patterns.length - 1) {
					data = Objects.deepClone(data);
				}
				this.fillProblemData(data, pattern, matches);
			}
		}
		let loop = !!this.patterns[this.patterns.length - 1].loop;
		if (!loop) {
			this.data = null;
		}
		const markerMatch = data ? this.getMarkerMatch(data) : null;
		return { match: markerMatch ? markerMatch : null, continue: loop };
	}

	public next(line: string): ProblemMatch | null {
		let pattern = this.patterns[this.patterns.length - 1];
		Assert.ok(pattern.loop === true && this.data !== null);
		let matches = pattern.regexp.exec(line);
		if (!matches) {
			this.data = null;
			return null;
		}
		let data = Objects.deepClone(this.data);
		let problemMatch: ProblemMatch | undefined;
		if (this.fillProblemData(data, pattern, matches)) {
			problemMatch = this.getMarkerMatch(data);
		}
		return problemMatch ? problemMatch : null;
	}
}

export namespace Config {

	export interface ProblemPattern {

		/**
		* The regular expression to find a problem in the console output of an
		* executed task.
		*/
		regexp?: string;

		/**
		* Whether the pattern matches a whole file, or a location (file/line)
		*
		* The default is to match for a location. Only valid on the
		* first problem pattern in a multi line problem matcher.
		*/
		kind?: string;

		/**
		* The match group index of the filename.
		* If omitted 1 is used.
		*/
		file?: number;

		/**
		* The match group index of the problem's location. Valid location
		* patterns are: (line), (line,column) and (startLine,startColumn,endLine,endColumn).
		* If omitted the line and column properties are used.
		*/
		location?: number;

		/**
		* The match group index of the problem's line in the source file.
		*
		* Defaults to 2.
		*/
		line?: number;

		/**
		* The match group index of the problem's column in the source file.
		*
		* Defaults to 3.
		*/
		column?: number;

		/**
		* The match group index of the problem's end line in the source file.
		*
		* Defaults to undefined. No end line is captured.
		*/
		endLine?: number;

		/**
		* The match group index of the problem's end column in the source file.
		*
		* Defaults to undefined. No end column is captured.
		*/
		endColumn?: number;

		/**
		* The match group index of the problem's severity.
		*
		* Defaults to undefined. In this case the problem matcher's severity
		* is used.
		*/
		severity?: number;

		/**
		* The match group index of the problem's code.
		*
		* Defaults to undefined. No code is captured.
		*/
		code?: number;

		/**
		* The match group index of the message. If omitted it defaults
		* to 4 if location is specified. Otherwise it defaults to 5.
		*/
		message?: number;

		/**
		* Specifies if the last pattern in a multi line problem matcher should
		* loop as long as it does match a line consequently. Only valid on the
		* last problem pattern in a multi line problem matcher.
		*/
		loop?: boolean;
	}

	export interface CheckedProblemPattern extends ProblemPattern {
		/**
		* The regular expression to find a problem in the console output of an
		* executed task.
		*/
		regexp: string;
	}

	export namespace CheckedProblemPattern {
		export function is(value: any): value is CheckedProblemPattern {
			let candidate: ProblemPattern = value as ProblemPattern;
			return candidate && Types.isString(candidate.regexp);
		}
	}

	export interface NamedProblemPattern extends ProblemPattern {
		/**
		 * The name of the problem pattern.
		 */
		name: string;

		/**
		 * A human readable label
		 */
		label?: string;
	}

	export namespace NamedProblemPattern {
		export function is(value: any): value is NamedProblemPattern {
			let candidate: NamedProblemPattern = value as NamedProblemPattern;
			return candidate && Types.isString(candidate.name);
		}
	}

	export interface NamedCheckedProblemPattern extends NamedProblemPattern {
		/**
		* The regular expression to find a problem in the console output of an
		* executed task.
		*/
		regexp: string;
	}

	export namespace NamedCheckedProblemPattern {
		export function is(value: any): value is NamedCheckedProblemPattern {
			let candidate: NamedProblemPattern = value as NamedProblemPattern;
			return candidate && NamedProblemPattern.is(candidate) && Types.isString(candidate.regexp);
		}
	}

	export type MultiLineProblemPattern = ProblemPattern[];

	export namespace MultiLineProblemPattern {
		export function is(value: any): value is MultiLineProblemPattern {
			return value && Types.isArray(value);
		}
	}

	export type MultiLineCheckedProblemPattern = CheckedProblemPattern[];

	export namespace MultiLineCheckedProblemPattern {
		export function is(value: any): value is MultiLineCheckedProblemPattern {
			if (!MultiLineProblemPattern.is(value)) {
				return false;
			}
			for (const element of value) {
				if (!Config.CheckedProblemPattern.is(element)) {
					return false;
				}
			}
			return true;
		}
	}

	export interface NamedMultiLineCheckedProblemPattern {
		/**
		 * The name of the problem pattern.
		 */
		name: string;

		/**
		 * A human readable label
		 */
		label?: string;

		/**
		 * The actual patterns
		 */
		patterns: MultiLineCheckedProblemPattern;
	}

	export namespace NamedMultiLineCheckedProblemPattern {
		export function is(value: any): value is NamedMultiLineCheckedProblemPattern {
			let candidate = value as NamedMultiLineCheckedProblemPattern;
			return candidate && Types.isString(candidate.name) && Types.isArray(candidate.patterns) && MultiLineCheckedProblemPattern.is(candidate.patterns);
		}
	}

	export type NamedProblemPatterns = (Config.NamedProblemPattern | Config.NamedMultiLineCheckedProblemPattern)[];

	/**
	* A watching pattern
	*/
	export interface WatchingPattern {
		/**
		* The actual regular expression
		*/
		regexp?: string;

		/**
		* The match group index of the filename. If provided the expression
		* is matched for that file only.
		*/
		file?: number;
	}

	/**
	* A description to track the start and end of a watching task.
	*/
	export interface BackgroundMonitor {

		/**
		* If set to true the watcher is in active mode when the task
		* starts. This is equals of issuing a line that matches the
		* beginsPattern.
		*/
		activeOnStart?: boolean;

		/**
		* If matched in the output the start of a watching task is signaled.
		*/
		beginsPattern?: string | WatchingPattern;

		/**
		* If matched in the output the end of a watching task is signaled.
		*/
		endsPattern?: string | WatchingPattern;
	}

	/**
	* A description of a problem matcher that detects problems
	* in build output.
	*/
	export interface ProblemMatcher {

		/**
		 * The name of a base problem matcher to use. If specified the
		 * base problem matcher will be used as a template and properties
		 * specified here will replace properties of the base problem
		 * matcher
		 */
		base?: string;

		/**
		 * The owner of the produced VSCode problem. This is typically
		 * the identifier of a VSCode language service if the problems are
		 * to be merged with the one produced by the language service
		 * or a generated internal id. Defaults to the generated internal id.
		 */
		owner?: string;

		/**
		 * A human-readable string describing the source of this problem.
		 * E.g. 'typescript' or 'super lint'.
		 */
		source?: string;

		/**
		* Specifies to which kind of documents the problems found by this
		* matcher are applied. Valid values are:
		*
		*   "allDocuments": problems found in all documents are applied.
		*   "openDocuments": problems found in documents that are open
		*   are applied.
		*   "closedDocuments": problems found in closed documents are
		*   applied.
		*/
		applyTo?: string;

		/**
		* The severity of the VSCode problem produced by this problem matcher.
		*
		* Valid values are:
		*   "error": to produce errors.
		*   "warning": to produce warnings.
		*   "info": to produce infos.
		*
		* The value is used if a pattern doesn't specify a severity match group.
		* Defaults to "error" if omitted.
		*/
		severity?: string;

		/**
		* Defines how filename reported in a problem pattern
		* should be read. Valid values are:
		*  - "absolute": the filename is always treated absolute.
		*  - "relative": the filename is always treated relative to
		*    the current working directory. This is the default.
		*  - ["relative", "path value"]: the filename is always
		*    treated relative to the given path value.
		*/
		fileLocation?: string | string[];

		/**
		* The name of a predefined problem pattern, the inline definintion
		* of a problem pattern or an array of problem patterns to match
		* problems spread over multiple lines.
		*/
		pattern?: string | ProblemPattern | ProblemPattern[];

		/**
		* A regular expression signaling that a watched tasks begins executing
		* triggered through file watching.
		*/
		watchedTaskBeginsRegExp?: string;

		/**
		* A regular expression signaling that a watched tasks ends executing.
		*/
		watchedTaskEndsRegExp?: string;

		/**
		 * @deprecated Use background instead.
		 */
		watching?: BackgroundMonitor;
		background?: BackgroundMonitor;
	}

	export type ProblemMatcherType = string | ProblemMatcher | Array<string | ProblemMatcher>;

	export interface NamedProblemMatcher extends ProblemMatcher {
		/**
		* This name can be used to refer to the
		* problem matcher from within a task.
		*/
		name: string;

		/**
		 * A human readable label.
		 */
		label?: string;
	}

	export function isNamedProblemMatcher(value: ProblemMatcher): value is NamedProblemMatcher {
		return Types.isString((<NamedProblemMatcher>value).name);
	}
}

export class ProblemPatternParser extends Parser {

	constructor(logger: IProblemReporter) {
		super(logger);
	}

	public parse(value: Config.ProblemPattern): ProblemPattern;
	public parse(value: Config.MultiLineProblemPattern): MultiLineProblemPattern;
	public parse(value: Config.NamedProblemPattern): NamedProblemPattern;
	public parse(value: Config.NamedMultiLineCheckedProblemPattern): NamedMultiLineProblemPattern;
	public parse(value: Config.ProblemPattern | Config.MultiLineProblemPattern | Config.NamedProblemPattern | Config.NamedMultiLineCheckedProblemPattern): any {
		if (Config.NamedMultiLineCheckedProblemPattern.is(value)) {
			return this.createNamedMultiLineProblemPattern(value);
		} else if (Config.MultiLineCheckedProblemPattern.is(value)) {
			return this.createMultiLineProblemPattern(value);
		} else if (Config.NamedCheckedProblemPattern.is(value)) {
			let result = this.createSingleProblemPattern(value) as NamedProblemPattern;
			result.name = value.name;
			return result;
		} else if (Config.CheckedProblemPattern.is(value)) {
			return this.createSingleProblemPattern(value);
		} else {
			this.error(localize('ProblemPatternParser.problemPattern.missingRegExp', 'The problem pattern is missing a regular expression.'));
			return null;
		}
	}

	private createSingleProblemPattern(value: Config.CheckedProblemPattern): ProblemPattern | null {
		let result = this.doCreateSingleProblemPattern(value, true);
		if (result === undefined) {
			return null;
		} else if (result.kind === undefined) {
			result.kind = ProblemLocationKind.Location;
		}
		return this.validateProblemPattern([result]) ? result : null;
	}

	private createNamedMultiLineProblemPattern(value: Config.NamedMultiLineCheckedProblemPattern): NamedMultiLineProblemPattern | null {
		const validPatterns = this.createMultiLineProblemPattern(value.patterns);
		if (!validPatterns) {
			return null;
		}
		let result = {
			name: value.name,
			label: value.label ? value.label : value.name,
			patterns: validPatterns
		};
		return result;
	}

	private createMultiLineProblemPattern(values: Config.MultiLineCheckedProblemPattern): MultiLineProblemPattern | null {
		let result: MultiLineProblemPattern = [];
		for (let i = 0; i < values.length; i++) {
			let pattern = this.doCreateSingleProblemPattern(values[i], false);
			if (pattern === undefined) {
				return null;
			}
			if (i < values.length - 1) {
				if (!Types.isUndefined(pattern.loop) && pattern.loop) {
					pattern.loop = false;
					this.error(localize('ProblemPatternParser.loopProperty.notLast', 'The loop property is only supported on the last line matcher.'));
				}
			}
			result.push(pattern);
		}
		if (result[0].kind === undefined) {
			result[0].kind = ProblemLocationKind.Location;
		}
		return this.validateProblemPattern(result) ? result : null;
	}

	private doCreateSingleProblemPattern(value: Config.CheckedProblemPattern, setDefaults: boolean): ProblemPattern | undefined {
		const regexp = this.createRegularExpression(value.regexp);
		if (regexp === undefined) {
			return undefined;
		}
		let result: ProblemPattern = { regexp };
		if (value.kind) {
			result.kind = ProblemLocationKind.fromString(value.kind);
		}

		function copyProperty(result: ProblemPattern, source: Config.ProblemPattern, resultKey: keyof ProblemPattern, sourceKey: keyof Config.ProblemPattern) {
			const value = source[sourceKey];
			if (typeof value === 'number') {
				(result as any)[resultKey] = value;
			}
		}
		copyProperty(result, value, 'file', 'file');
		copyProperty(result, value, 'location', 'location');
		copyProperty(result, value, 'line', 'line');
		copyProperty(result, value, 'character', 'column');
		copyProperty(result, value, 'endLine', 'endLine');
		copyProperty(result, value, 'endCharacter', 'endColumn');
		copyProperty(result, value, 'severity', 'severity');
		copyProperty(result, value, 'code', 'code');
		copyProperty(result, value, 'message', 'message');
		if (value.loop === true || value.loop === false) {
			result.loop = value.loop;
		}
		if (setDefaults) {
			if (result.location || result.kind === ProblemLocationKind.File) {
				let defaultValue: Partial<ProblemPattern> = {
					file: 1,
					message: 0
				};
				result = Objects.mixin(result, defaultValue, false);
			} else {
				let defaultValue: Partial<ProblemPattern> = {
					file: 1,
					line: 2,
					character: 3,
					message: 0
				};
				result = Objects.mixin(result, defaultValue, false);
			}
		}
		return result;
	}

	private validateProblemPattern(values: ProblemPattern[]): boolean {
		let file: boolean = false, message: boolean = false, location: boolean = false, line: boolean = false;
		let locationKind = (values[0].kind === undefined) ? ProblemLocationKind.Location : values[0].kind;

		values.forEach((pattern, i) => {
			if (i !== 0 && pattern.kind) {
				this.error(localize('ProblemPatternParser.problemPattern.kindProperty.notFirst', 'The problem pattern is invalid. The kind property must be provided only in the first element'));
			}
			file = file || !Types.isUndefined(pattern.file);
			message = message || !Types.isUndefined(pattern.message);
			location = location || !Types.isUndefined(pattern.location);
			line = line || !Types.isUndefined(pattern.line);
		});
		if (!(file && message)) {
			this.error(localize('ProblemPatternParser.problemPattern.missingProperty', 'The problem pattern is invalid. It must have at least have a file and a message.'));
			return false;
		}
		if (locationKind === ProblemLocationKind.Location && !(location || line)) {
			this.error(localize('ProblemPatternParser.problemPattern.missingLocation', 'The problem pattern is invalid. It must either have kind: "file" or have a line or location match group.'));
			return false;
		}
		return true;
	}

	private createRegularExpression(value: string): RegExp | undefined {
		let result: RegExp | undefined;
		try {
			result = new RegExp(value);
		} catch (err) {
			this.error(localize('ProblemPatternParser.invalidRegexp', 'Error: The string {0} is not a valid regular expression.\n', value));
		}
		return result;
	}
}

export class ExtensionRegistryReporter implements IProblemReporter {
	constructor(private _collector: ExtensionMessageCollector, private _validationStatus: ValidationStatus = new ValidationStatus()) {
	}

	public info(message: string): void {
		this._validationStatus.state = ValidationState.Info;
		this._collector.info(message);
	}

	public warn(message: string): void {
		this._validationStatus.state = ValidationState.Warning;
		this._collector.warn(message);
	}

	public error(message: string): void {
		this._validationStatus.state = ValidationState.Error;
		this._collector.error(message);
	}

	public fatal(message: string): void {
		this._validationStatus.state = ValidationState.Fatal;
		this._collector.error(message);
	}

	public get status(): ValidationStatus {
		return this._validationStatus;
	}
}

export namespace Schemas {

	export const ProblemPattern: IJSONSchema = {
		default: {
			regexp: '^([^\\\\s].*)\\\\((\\\\d+,\\\\d+)\\\\):\\\\s*(.*)$',
			file: 1,
			location: 2,
			message: 3
		},
		type: 'object',
		additionalProperties: false,
		properties: {
			regexp: {
				type: 'string',
				description: localize('ProblemPatternSchema.regexp', 'The regular expression to find an error, warning or info in the output.')
			},
			kind: {
				type: 'string',
				description: localize('ProblemPatternSchema.kind', 'whether the pattern matches a location (file and line) or only a file.')
			},
			file: {
				type: 'integer',
				description: localize('ProblemPatternSchema.file', 'The match group index of the filename. If omitted 1 is used.')
			},
			location: {
				type: 'integer',
				description: localize('ProblemPatternSchema.location', 'The match group index of the problem\'s location. Valid location patterns are: (line), (line,column) and (startLine,startColumn,endLine,endColumn). If omitted (line,column) is assumed.')
			},
			line: {
				type: 'integer',
				description: localize('ProblemPatternSchema.line', 'The match group index of the problem\'s line. Defaults to 2')
			},
			column: {
				type: 'integer',
				description: localize('ProblemPatternSchema.column', 'The match group index of the problem\'s line character. Defaults to 3')
			},
			endLine: {
				type: 'integer',
				description: localize('ProblemPatternSchema.endLine', 'The match group index of the problem\'s end line. Defaults to undefined')
			},
			endColumn: {
				type: 'integer',
				description: localize('ProblemPatternSchema.endColumn', 'The match group index of the problem\'s end line character. Defaults to undefined')
			},
			severity: {
				type: 'integer',
				description: localize('ProblemPatternSchema.severity', 'The match group index of the problem\'s severity. Defaults to undefined')
			},
			code: {
				type: 'integer',
				description: localize('ProblemPatternSchema.code', 'The match group index of the problem\'s code. Defaults to undefined')
			},
			message: {
				type: 'integer',
				description: localize('ProblemPatternSchema.message', 'The match group index of the message. If omitted it defaults to 4 if location is specified. Otherwise it defaults to 5.')
			},
			loop: {
				type: 'boolean',
				description: localize('ProblemPatternSchema.loop', 'In a multi line matcher loop indicated whether this pattern is executed in a loop as long as it matches. Can only specified on a last pattern in a multi line pattern.')
			}
		}
	};

	export const NamedProblemPattern: IJSONSchema = Objects.deepClone(ProblemPattern);
	NamedProblemPattern.properties = Objects.deepClone(NamedProblemPattern.properties) || {};
	NamedProblemPattern.properties['name'] = {
		type: 'string',
		description: localize('NamedProblemPatternSchema.name', 'The name of the problem pattern.')
	};

	export const MultiLineProblemPattern: IJSONSchema = {
		type: 'array',
		items: ProblemPattern
	};

	export const NamedMultiLineProblemPattern: IJSONSchema = {
		type: 'object',
		additionalProperties: false,
		properties: {
			name: {
				type: 'string',
				description: localize('NamedMultiLineProblemPatternSchema.name', 'The name of the problem multi line problem pattern.')
			},
			patterns: {
				type: 'array',
				description: localize('NamedMultiLineProblemPatternSchema.patterns', 'The actual patterns.'),
				items: ProblemPattern
			}
		}
	};
}

const problemPatternExtPoint = ExtensionsRegistry.registerExtensionPoint<Config.NamedProblemPatterns>({
	extensionPoint: 'problemPatterns',
	jsonSchema: {
		description: localize('ProblemPatternExtPoint', 'Contributes problem patterns'),
		type: 'array',
		items: {
			anyOf: [
				Schemas.NamedProblemPattern,
				Schemas.NamedMultiLineProblemPattern
			]
		}
	}
});

export interface IProblemPatternRegistry {
	onReady(): Promise<void>;

	get(key: string): ProblemPattern | MultiLineProblemPattern;
}

class ProblemPatternRegistryImpl implements IProblemPatternRegistry {

	private patterns: IStringDictionary<ProblemPattern | ProblemPattern[]>;
	private readyPromise: Promise<void>;

	constructor() {
		this.patterns = Object.create(null);
		this.fillDefaults();
		this.readyPromise = new Promise<void>((resolve, reject) => {
			problemPatternExtPoint.setHandler((extensions, delta) => {
				// We get all statically know extension during startup in one batch
				try {
					delta.removed.forEach(extension => {
						let problemPatterns = extension.value as Config.NamedProblemPatterns;
						for (let pattern of problemPatterns) {
							if (this.patterns[pattern.name]) {
								delete this.patterns[pattern.name];
							}
						}
					});
					delta.added.forEach(extension => {
						let problemPatterns = extension.value as Config.NamedProblemPatterns;
						let parser = new ProblemPatternParser(new ExtensionRegistryReporter(extension.collector));
						for (let pattern of problemPatterns) {
							if (Config.NamedMultiLineCheckedProblemPattern.is(pattern)) {
								let result = parser.parse(pattern);
								if (parser.problemReporter.status.state < ValidationState.Error) {
									this.add(result.name, result.patterns);
								} else {
									extension.collector.error(localize('ProblemPatternRegistry.error', 'Invalid problem pattern. The pattern will be ignored.'));
									extension.collector.error(JSON.stringify(pattern, undefined, 4));
								}
							}
							else if (Config.NamedProblemPattern.is(pattern)) {
								let result = parser.parse(pattern);
								if (parser.problemReporter.status.state < ValidationState.Error) {
									this.add(pattern.name, result);
								} else {
									extension.collector.error(localize('ProblemPatternRegistry.error', 'Invalid problem pattern. The pattern will be ignored.'));
									extension.collector.error(JSON.stringify(pattern, undefined, 4));
								}
							}
							parser.reset();
						}
					});
				} catch (error) {
					// Do nothing
				}
				resolve(undefined);
			});
		});
	}

	public onReady(): Promise<void> {
		return this.readyPromise;
	}

	public add(key: string, value: ProblemPattern | ProblemPattern[]): void {
		this.patterns[key] = value;
	}

	public get(key: string): ProblemPattern | ProblemPattern[] {
		return this.patterns[key];
	}

	private fillDefaults(): void {
		this.add('msCompile', {
			regexp: /^(?:\s+\d+\>)?([^\s].*)\((\d+|\d+,\d+|\d+,\d+,\d+,\d+)\)\s*:\s+(error|warning|info)\s+(\w{1,2}\d+)\s*:\s*(.*)$/,
			kind: ProblemLocationKind.Location,
			file: 1,
			location: 2,
			severity: 3,
			code: 4,
			message: 5
		});
		this.add('gulp-tsc', {
			regexp: /^([^\s].*)\((\d+|\d+,\d+|\d+,\d+,\d+,\d+)\):\s+(\d+)\s+(.*)$/,
			kind: ProblemLocationKind.Location,
			file: 1,
			location: 2,
			code: 3,
			message: 4
		});
		this.add('cpp', {
			regexp: /^([^\s].*)\((\d+|\d+,\d+|\d+,\d+,\d+,\d+)\):\s+(error|warning|info)\s+(C\d+)\s*:\s*(.*)$/,
			kind: ProblemLocationKind.Location,
			file: 1,
			location: 2,
			severity: 3,
			code: 4,
			message: 5
		});
		this.add('csc', {
			regexp: /^([^\s].*)\((\d+|\d+,\d+|\d+,\d+,\d+,\d+)\):\s+(error|warning|info)\s+(CS\d+)\s*:\s*(.*)$/,
			kind: ProblemLocationKind.Location,
			file: 1,
			location: 2,
			severity: 3,
			code: 4,
			message: 5
		});
		this.add('vb', {
			regexp: /^([^\s].*)\((\d+|\d+,\d+|\d+,\d+,\d+,\d+)\):\s+(error|warning|info)\s+(BC\d+)\s*:\s*(.*)$/,
			kind: ProblemLocationKind.Location,
			file: 1,
			location: 2,
			severity: 3,
			code: 4,
			message: 5
		});
		this.add('lessCompile', {
			regexp: /^\s*(.*) in file (.*) line no. (\d+)$/,
			kind: ProblemLocationKind.Location,
			message: 1,
			file: 2,
			line: 3
		});
		this.add('jshint', {
			regexp: /^(.*):\s+line\s+(\d+),\s+col\s+(\d+),\s(.+?)(?:\s+\((\w)(\d+)\))?$/,
			kind: ProblemLocationKind.Location,
			file: 1,
			line: 2,
			character: 3,
			message: 4,
			severity: 5,
			code: 6
		});
		this.add('jshint-stylish', [
			{
				regexp: /^(.+)$/,
				kind: ProblemLocationKind.Location,
				file: 1
			},
			{
				regexp: /^\s+line\s+(\d+)\s+col\s+(\d+)\s+(.+?)(?:\s+\((\w)(\d+)\))?$/,
				line: 1,
				character: 2,
				message: 3,
				severity: 4,
				code: 5,
				loop: true
			}
		]);
		this.add('eslint-compact', {
			regexp: /^(.+):\sline\s(\d+),\scol\s(\d+),\s(Error|Warning|Info)\s-\s(.+)\s\((.+)\)$/,
			file: 1,
			kind: ProblemLocationKind.Location,
			line: 2,
			character: 3,
			severity: 4,
			message: 5,
			code: 6
		});
		this.add('eslint-stylish', [
			{
				regexp: /^([^\s].*)$/,
				kind: ProblemLocationKind.Location,
				file: 1
			},
			{
				regexp: /^\s+(\d+):(\d+)\s+(error|warning|info)\s+(.+?)(?:\s\s+(.*))?$/,
				line: 1,
				character: 2,
				severity: 3,
				message: 4,
				code: 5,
				loop: true
			}
		]);
		this.add('go', {
			regexp: /^([^:]*: )?((.:)?[^:]*):(\d+)(:(\d+))?: (.*)$/,
			kind: ProblemLocationKind.Location,
			file: 2,
			line: 4,
			character: 6,
			message: 7
		});
	}
}

export const ProblemPatternRegistry: IProblemPatternRegistry = new ProblemPatternRegistryImpl();

export class ProblemMatcherParser extends Parser {

	constructor(logger: IProblemReporter) {
		super(logger);
	}

	public parse(json: Config.ProblemMatcher): ProblemMatcher | undefined {
		let result = this.createProblemMatcher(json);
		if (!this.checkProblemMatcherValid(json, result)) {
			return undefined;
		}
		this.addWatchingMatcher(json, result);

		return result;
	}

	private checkProblemMatcherValid(externalProblemMatcher: Config.ProblemMatcher, problemMatcher: ProblemMatcher | null): problemMatcher is ProblemMatcher {
		if (!problemMatcher) {
			this.error(localize('ProblemMatcherParser.noProblemMatcher', 'Error: the description can\'t be converted into a problem matcher:\n{0}\n', JSON.stringify(externalProblemMatcher, null, 4)));
			return false;
		}
		if (!problemMatcher.pattern) {
			this.error(localize('ProblemMatcherParser.noProblemPattern', 'Error: the description doesn\'t define a valid problem pattern:\n{0}\n', JSON.stringify(externalProblemMatcher, null, 4)));
			return false;
		}
		if (!problemMatcher.owner) {
			this.error(localize('ProblemMatcherParser.noOwner', 'Error: the description doesn\'t define an owner:\n{0}\n', JSON.stringify(externalProblemMatcher, null, 4)));
			return false;
		}
		if (Types.isUndefined(problemMatcher.fileLocation)) {
			this.error(localize('ProblemMatcherParser.noFileLocation', 'Error: the description doesn\'t define a file location:\n{0}\n', JSON.stringify(externalProblemMatcher, null, 4)));
			return false;
		}
		return true;
	}

	private createProblemMatcher(description: Config.ProblemMatcher): ProblemMatcher | null {
		let result: ProblemMatcher | null = null;

		let owner = Types.isString(description.owner) ? description.owner : UUID.generateUuid();
		let source = Types.isString(description.source) ? description.source : undefined;
		let applyTo = Types.isString(description.applyTo) ? ApplyToKind.fromString(description.applyTo) : ApplyToKind.allDocuments;
		if (!applyTo) {
			applyTo = ApplyToKind.allDocuments;
		}
		let fileLocation: FileLocationKind | undefined = undefined;
		let filePrefix: string | undefined = undefined;

		let kind: FileLocationKind | undefined;
		if (Types.isUndefined(description.fileLocation)) {
			fileLocation = FileLocationKind.Relative;
			filePrefix = '${workspaceFolder}';
		} else if (Types.isString(description.fileLocation)) {
			kind = FileLocationKind.fromString(<string>description.fileLocation);
			if (kind) {
				fileLocation = kind;
				if ((kind === FileLocationKind.Relative) || (kind === FileLocationKind.AutoDetect)) {
					filePrefix = '${workspaceFolder}';
				}
			}
		} else if (Types.isStringArray(description.fileLocation)) {
			let values = <string[]>description.fileLocation;
			if (values.length > 0) {
				kind = FileLocationKind.fromString(values[0]);
				if (values.length === 1 && kind === FileLocationKind.Absolute) {
					fileLocation = kind;
				} else if (values.length === 2 && (kind === FileLocationKind.Relative || kind === FileLocationKind.AutoDetect) && values[1]) {
					fileLocation = kind;
					filePrefix = values[1];
				}
			}
		}

		let pattern = description.pattern ? this.createProblemPattern(description.pattern) : undefined;

		let severity = description.severity ? Severity.fromValue(description.severity) : undefined;
		if (severity === Severity.Ignore) {
			this.info(localize('ProblemMatcherParser.unknownSeverity', 'Info: unknown severity {0}. Valid values are error, warning and info.\n', description.severity));
			severity = Severity.Error;
		}

		if (Types.isString(description.base)) {
			let variableName = <string>description.base;
			if (variableName.length > 1 && variableName[0] === '$') {
				let base = ProblemMatcherRegistry.get(variableName.substring(1));
				if (base) {
					result = Objects.deepClone(base);
					if (description.owner !== undefined && owner !== undefined) {
						result.owner = owner;
					}
					if (description.source !== undefined && source !== undefined) {
						result.source = source;
					}
					if (description.fileLocation !== undefined && fileLocation !== undefined) {
						result.fileLocation = fileLocation;
						result.filePrefix = filePrefix;
					}
					if (description.pattern !== undefined && pattern !== undefined && pattern !== null) {
						result.pattern = pattern;
					}
					if (description.severity !== undefined && severity !== undefined) {
						result.severity = severity;
					}
					if (description.applyTo !== undefined && applyTo !== undefined) {
						result.applyTo = applyTo;
					}
				}
			}
		} else if (fileLocation && pattern) {
			result = {
				owner: owner,
				applyTo: applyTo,
				fileLocation: fileLocation,
				pattern: pattern,
			};
			if (source) {
				result.source = source;
			}
			if (filePrefix) {
				result.filePrefix = filePrefix;
			}
			if (severity) {
				result.severity = severity;
			}
		}
		if (Config.isNamedProblemMatcher(description)) {
			(result as NamedProblemMatcher).name = description.name;
			(result as NamedProblemMatcher).label = Types.isString(description.label) ? description.label : description.name;
		}
		return result;
	}

	private createProblemPattern(value: string | Config.ProblemPattern | Config.MultiLineProblemPattern): ProblemPattern | ProblemPattern[] | null {
		if (Types.isString(value)) {
			let variableName: string = <string>value;
			if (variableName.length > 1 && variableName[0] === '$') {
				let result = ProblemPatternRegistry.get(variableName.substring(1));
				if (!result) {
					this.error(localize('ProblemMatcherParser.noDefinedPatter', 'Error: the pattern with the identifier {0} doesn\'t exist.', variableName));
				}
				return result;
			} else {
				if (variableName.length === 0) {
					this.error(localize('ProblemMatcherParser.noIdentifier', 'Error: the pattern property refers to an empty identifier.'));
				} else {
					this.error(localize('ProblemMatcherParser.noValidIdentifier', 'Error: the pattern property {0} is not a valid pattern variable name.', variableName));
				}
			}
		} else if (value) {
			let problemPatternParser = new ProblemPatternParser(this.problemReporter);
			if (Array.isArray(value)) {
				return problemPatternParser.parse(value);
			} else {
				return problemPatternParser.parse(value);
			}
		}
		return null;
	}

	private addWatchingMatcher(external: Config.ProblemMatcher, internal: ProblemMatcher): void {
		let oldBegins = this.createRegularExpression(external.watchedTaskBeginsRegExp);
		let oldEnds = this.createRegularExpression(external.watchedTaskEndsRegExp);
		if (oldBegins && oldEnds) {
			internal.watching = {
				activeOnStart: false,
				beginsPattern: { regexp: oldBegins },
				endsPattern: { regexp: oldEnds }
			};
			return;
		}
		let backgroundMonitor = external.background || external.watching;
		if (Types.isUndefinedOrNull(backgroundMonitor)) {
			return;
		}
		let begins: WatchingPattern | null = this.createWatchingPattern(backgroundMonitor.beginsPattern);
		let ends: WatchingPattern | null = this.createWatchingPattern(backgroundMonitor.endsPattern);
		if (begins && ends) {
			internal.watching = {
				activeOnStart: Types.isBoolean(backgroundMonitor.activeOnStart) ? backgroundMonitor.activeOnStart : false,
				beginsPattern: begins,
				endsPattern: ends
			};
			return;
		}
		if (begins || ends) {
			this.error(localize('ProblemMatcherParser.problemPattern.watchingMatcher', 'A problem matcher must define both a begin pattern and an end pattern for watching.'));
		}
	}

	private createWatchingPattern(external: string | Config.WatchingPattern | undefined): WatchingPattern | null {
		if (Types.isUndefinedOrNull(external)) {
			return null;
		}
		let regexp: RegExp | null;
		let file: number | undefined;
		if (Types.isString(external)) {
			regexp = this.createRegularExpression(external);
		} else {
			regexp = this.createRegularExpression(external.regexp);
			if (Types.isNumber(external.file)) {
				file = external.file;
			}
		}
		if (!regexp) {
			return null;
		}
		return file ? { regexp, file } : { regexp, file: 1 };
	}

	private createRegularExpression(value: string | undefined): RegExp | null {
		let result: RegExp | null = null;
		if (!value) {
			return result;
		}
		try {
			result = new RegExp(value);
		} catch (err) {
			this.error(localize('ProblemMatcherParser.invalidRegexp', 'Error: The string {0} is not a valid regular expression.\n', value));
		}
		return result;
	}
}

export namespace Schemas {

	export const WatchingPattern: IJSONSchema = {
		type: 'object',
		additionalProperties: false,
		properties: {
			regexp: {
				type: 'string',
				description: localize('WatchingPatternSchema.regexp', 'The regular expression to detect the begin or end of a background task.')
			},
			file: {
				type: 'integer',
				description: localize('WatchingPatternSchema.file', 'The match group index of the filename. Can be omitted.')
			},
		}
	};

	export const PatternType: IJSONSchema = {
		anyOf: [
			{
				type: 'string',
				description: localize('PatternTypeSchema.name', 'The name of a contributed or predefined pattern')
			},
			Schemas.ProblemPattern,
			Schemas.MultiLineProblemPattern
		],
		description: localize('PatternTypeSchema.description', 'A problem pattern or the name of a contributed or predefined problem pattern. Can be omitted if base is specified.')
	};

	export const ProblemMatcher: IJSONSchema = {
		type: 'object',
		additionalProperties: false,
		properties: {
			base: {
				type: 'string',
				description: localize('ProblemMatcherSchema.base', 'The name of a base problem matcher to use.')
			},
			owner: {
				type: 'string',
				description: localize('ProblemMatcherSchema.owner', 'The owner of the problem inside Code. Can be omitted if base is specified. Defaults to \'external\' if omitted and base is not specified.')
			},
			source: {
				type: 'string',
				description: localize('ProblemMatcherSchema.source', 'A human-readable string describing the source of this diagnostic, e.g. \'typescript\' or \'super lint\'.')
			},
			severity: {
				type: 'string',
				enum: ['error', 'warning', 'info'],
				description: localize('ProblemMatcherSchema.severity', 'The default severity for captures problems. Is used if the pattern doesn\'t define a match group for severity.')
			},
			applyTo: {
				type: 'string',
				enum: ['allDocuments', 'openDocuments', 'closedDocuments'],
				description: localize('ProblemMatcherSchema.applyTo', 'Controls if a problem reported on a text document is applied only to open, closed or all documents.')
			},
			pattern: PatternType,
			fileLocation: {
				oneOf: [
					{
						type: 'string',
						enum: ['absolute', 'relative', 'autoDetect']
					},
					{
						type: 'array',
						items: {
							type: 'string'
						}
					}
				],
				description: localize('ProblemMatcherSchema.fileLocation', 'Defines how file names reported in a problem pattern should be interpreted.')
			},
			background: {
				type: 'object',
				additionalProperties: false,
				description: localize('ProblemMatcherSchema.background', 'Patterns to track the begin and end of a matcher active on a background task.'),
				properties: {
					activeOnStart: {
						type: 'boolean',
						description: localize('ProblemMatcherSchema.background.activeOnStart', 'If set to true the background monitor is in active mode when the task starts. This is equals of issuing a line that matches the beginsPattern')
					},
					beginsPattern: {
						oneOf: [
							{
								type: 'string'
							},
							Schemas.WatchingPattern
						],
						description: localize('ProblemMatcherSchema.background.beginsPattern', 'If matched in the output the start of a background task is signaled.')
					},
					endsPattern: {
						oneOf: [
							{
								type: 'string'
							},
							Schemas.WatchingPattern
						],
						description: localize('ProblemMatcherSchema.background.endsPattern', 'If matched in the output the end of a background task is signaled.')
					}
				}
			},
			watching: {
				type: 'object',
				additionalProperties: false,
				deprecationMessage: localize('ProblemMatcherSchema.watching.deprecated', 'The watching property is deprecated. Use background instead.'),
				description: localize('ProblemMatcherSchema.watching', 'Patterns to track the begin and end of a watching matcher.'),
				properties: {
					activeOnStart: {
						type: 'boolean',
						description: localize('ProblemMatcherSchema.watching.activeOnStart', 'If set to true the watcher is in active mode when the task starts. This is equals of issuing a line that matches the beginPattern')
					},
					beginsPattern: {
						oneOf: [
							{
								type: 'string'
							},
							Schemas.WatchingPattern
						],
						description: localize('ProblemMatcherSchema.watching.beginsPattern', 'If matched in the output the start of a watching task is signaled.')
					},
					endsPattern: {
						oneOf: [
							{
								type: 'string'
							},
							Schemas.WatchingPattern
						],
						description: localize('ProblemMatcherSchema.watching.endsPattern', 'If matched in the output the end of a watching task is signaled.')
					}
				}
			}
		}
	};

	export const LegacyProblemMatcher: IJSONSchema = Objects.deepClone(ProblemMatcher);
	LegacyProblemMatcher.properties = Objects.deepClone(LegacyProblemMatcher.properties) || {};
	LegacyProblemMatcher.properties['watchedTaskBeginsRegExp'] = {
		type: 'string',
		deprecationMessage: localize('LegacyProblemMatcherSchema.watchedBegin.deprecated', 'This property is deprecated. Use the watching property instead.'),
		description: localize('LegacyProblemMatcherSchema.watchedBegin', 'A regular expression signaling that a watched tasks begins executing triggered through file watching.')
	};
	LegacyProblemMatcher.properties['watchedTaskEndsRegExp'] = {
		type: 'string',
		deprecationMessage: localize('LegacyProblemMatcherSchema.watchedEnd.deprecated', 'This property is deprecated. Use the watching property instead.'),
		description: localize('LegacyProblemMatcherSchema.watchedEnd', 'A regular expression signaling that a watched tasks ends executing.')
	};

	export const NamedProblemMatcher: IJSONSchema = Objects.deepClone(ProblemMatcher);
	NamedProblemMatcher.properties = Objects.deepClone(NamedProblemMatcher.properties) || {};
	NamedProblemMatcher.properties.name = {
		type: 'string',
		description: localize('NamedProblemMatcherSchema.name', 'The name of the problem matcher used to refer to it.')
	};
	NamedProblemMatcher.properties.label = {
		type: 'string',
		description: localize('NamedProblemMatcherSchema.label', 'A human readable label of the problem matcher.')
	};
}

const problemMatchersExtPoint = ExtensionsRegistry.registerExtensionPoint<Config.NamedProblemMatcher[]>({
	extensionPoint: 'problemMatchers',
	deps: [problemPatternExtPoint],
	jsonSchema: {
		description: localize('ProblemMatcherExtPoint', 'Contributes problem matchers'),
		type: 'array',
		items: Schemas.NamedProblemMatcher
	}
});

export interface IProblemMatcherRegistry {
	onReady(): Promise<void>;
	get(name: string): NamedProblemMatcher;
	keys(): string[];
	readonly onMatcherChanged: Event<void>;
}

class ProblemMatcherRegistryImpl implements IProblemMatcherRegistry {

	private matchers: IStringDictionary<NamedProblemMatcher>;
	private readyPromise: Promise<void>;
	private readonly _onMatchersChanged: Emitter<void> = new Emitter<void>();
	public get onMatcherChanged(): Event<void> { return this._onMatchersChanged.event; }

	constructor() {
		this.matchers = Object.create(null);
		this.fillDefaults();
		this.readyPromise = new Promise<void>((resolve, reject) => {
			problemMatchersExtPoint.setHandler((extensions, delta) => {
				try {
					delta.removed.forEach(extension => {
						let problemMatchers = extension.value;
						for (let matcher of problemMatchers) {
							if (this.matchers[matcher.name]) {
								delete this.matchers[matcher.name];
							}
						}
					});
					delta.added.forEach(extension => {
						let problemMatchers = extension.value;
						let parser = new ProblemMatcherParser(new ExtensionRegistryReporter(extension.collector));
						for (let matcher of problemMatchers) {
							let result = parser.parse(matcher);
							if (result && isNamedProblemMatcher(result)) {
								this.add(result);
							}
						}
					});
					if ((delta.removed.length > 0) || (delta.added.length > 0)) {
						this._onMatchersChanged.fire();
					}
				} catch (error) {
				}
				let matcher = this.get('tsc-watch');
				if (matcher) {
					(<any>matcher).tscWatch = true;
				}
				resolve(undefined);
			});
		});
	}

	public onReady(): Promise<void> {
		ProblemPatternRegistry.onReady();
		return this.readyPromise;
	}

	public add(matcher: NamedProblemMatcher): void {
		this.matchers[matcher.name] = matcher;
	}

	public get(name: string): NamedProblemMatcher {
		return this.matchers[name];
	}

	public keys(): string[] {
		return Object.keys(this.matchers);
	}

	private fillDefaults(): void {
		this.add({
			name: 'msCompile',
			label: localize('msCompile', 'Microsoft compiler problems'),
			owner: 'msCompile',
			applyTo: ApplyToKind.allDocuments,
			fileLocation: FileLocationKind.Absolute,
			pattern: ProblemPatternRegistry.get('msCompile')
		});

		this.add({
			name: 'lessCompile',
			label: localize('lessCompile', 'Less problems'),
			deprecated: true,
			owner: 'lessCompile',
			source: 'less',
			applyTo: ApplyToKind.allDocuments,
			fileLocation: FileLocationKind.Absolute,
			pattern: ProblemPatternRegistry.get('lessCompile'),
			severity: Severity.Error
		});

		this.add({
			name: 'gulp-tsc',
			label: localize('gulp-tsc', 'Gulp TSC Problems'),
			owner: 'typescript',
			source: 'ts',
			applyTo: ApplyToKind.closedDocuments,
			fileLocation: FileLocationKind.Relative,
			filePrefix: '${workspaceFolder}',
			pattern: ProblemPatternRegistry.get('gulp-tsc')
		});

		this.add({
			name: 'jshint',
			label: localize('jshint', 'JSHint problems'),
			owner: 'jshint',
			source: 'jshint',
			applyTo: ApplyToKind.allDocuments,
			fileLocation: FileLocationKind.Absolute,
			pattern: ProblemPatternRegistry.get('jshint')
		});

		this.add({
			name: 'jshint-stylish',
			label: localize('jshint-stylish', 'JSHint stylish problems'),
			owner: 'jshint',
			source: 'jshint',
			applyTo: ApplyToKind.allDocuments,
			fileLocation: FileLocationKind.Absolute,
			pattern: ProblemPatternRegistry.get('jshint-stylish')
		});

		this.add({
			name: 'eslint-compact',
			label: localize('eslint-compact', 'ESLint compact problems'),
			owner: 'eslint',
			source: 'eslint',
			applyTo: ApplyToKind.allDocuments,
			fileLocation: FileLocationKind.Absolute,
			filePrefix: '${workspaceFolder}',
			pattern: ProblemPatternRegistry.get('eslint-compact')
		});

		this.add({
			name: 'eslint-stylish',
			label: localize('eslint-stylish', 'ESLint stylish problems'),
			owner: 'eslint',
			source: 'eslint',
			applyTo: ApplyToKind.allDocuments,
			fileLocation: FileLocationKind.Absolute,
			pattern: ProblemPatternRegistry.get('eslint-stylish')
		});

		this.add({
			name: 'go',
			label: localize('go', 'Go problems'),
			owner: 'go',
			source: 'go',
			applyTo: ApplyToKind.allDocuments,
			fileLocation: FileLocationKind.Relative,
			filePrefix: '${workspaceFolder}',
			pattern: ProblemPatternRegistry.get('go')
		});
	}
}

export const ProblemMatcherRegistry: IProblemMatcherRegistry = new ProblemMatcherRegistryImpl();

redpajama_set_name: RedPajamaGithub


West London Aero Club Engineering is an EASA PART 145 and CAA Subpart G approved maintenance facility. Our team of experienced engineers are equipped to inspect and repair a large range of aircraft. We also have a technical records department to handle aircraft hours, records and engineering logs if required, and a comprehensive stores facility. Contact us for full details of our engineering rates.


text:
Derbyshire captain Wayne Madsen signs three-year deal
Last updated on 17 October 201217 October 2012 .From the section Cricket
Derbyshire captain Wayne Madsen has signed a new three-year contract that keeps him with the club until the end of the 2015 season.
Madsen, 28, led Derbyshire to the County Championship Division Two title in 2012 in his first season as captain.
"What we achieved was incredible and this is a club that's growing and moving in the right direction on and off the field," said Madsen.
"To be here for another three seasons is fantastic."
He added: "To lead this squad is a great honour; I'm so excited about where we are heading and we're looking forward to challenging ourselves in Division One next season."
Derbyshire return to the big time
Wayne Madsen guided Derbyshire to the County Championship Division Two title in 2012 in his first year as club captain.
In 2013, Derbyshire will be playing in English cricket's top flight for the first season since 2000.
South Africa-born Madsen made his Derbyshire debut in 2009 and has played 56 first-class matches, scoring 3,401 runs at an average of 36.21 with 12 centuries.
He has also scored 1,110 runs in 35 one-day games and 510 runs in 35 Twenty20 outings.
In 2012, he made three centuries in the County Championship, including a career-best 231 not out in Derbyshire's game against Northants in August.
"You can see by his record that Wayne is a fine player," said Derbyshire head coach Karl Krikken.
"He has topped our run-scoring in first-class cricket in 2012 and, with that double-hundred at Northampton, he produced one of the most vital performances of the year.
"The way he has led the side this season, in his first year in the job, has been absolutely magnificent.
"He's got a great captaincy style and the example he sets the younger players in terms of his work ethic is fantastic.
"I'm delighted we're continuing to work together to keep taking the club forward."
Madsen becomes the latest player to commit his future to Derbyshire after Dan Redfern, Wes Durston, Jonathan Clare, Tony Palladino and Ross Whiteley agreed new contracts.
Australian Open: Nadal a set up after defending champion Osaka beaten - radio & text
Osaka's title defence over in Melbourne
9m9 minutes ago
Premier League build-up and transfers latest

redpajama_set_name: RedPajamaCommonCrawl


The Women's Institute is about much more than just good cake.
101 years after it arrived in England and Wales, the all-female organisation is still going strong, with 215,000 members across 6,500 WI groups nationwide.
And Dorothy Meekins has a good idea why its popularity has remained throughout the last century - and it has very little to do with cake.
"The WI plays a unique role in providing women with educational opportunities and the chance to build new skills," explains the 67-year-old.
And as chairwoman of the South Yorkshire Women's Institute Federation for the last five years, Dorothy oversees 2,814 members in 69 thriving WI groups in villages, towns and cities throughout the region.
"Friendship plays a big part in it too," says Dorothy, who joined the WI 11 years ago, after retiring from her job as a midwife.
The WI is open to all women aged 18 or over and, though Dorothy reveals the average age of a member is around 60, she says the organisation has seen a real surge in younger members.
"We've seen things like knitting, sewing and home-cooking make a comeback in recent years," says Dorothy.
Dorothy explains that each WI group is independent and responsible for organising their own schedule of events and activities - which can range from talks and craft groups, to wine tasting sessions and history walks; all under the education banner.
And the fascinating history of WI is something Dorothy says most people have never heard.
"Most people have no idea it all began back in 1897 in Canada, with one woman whose child died of food poisoning," she says.
The organisation made its way to this country in 1915, to encourage women to become more involved in producing food during the First World War. In the years since, the organisation's aims have broadened and the WI is now the largest voluntary women's organisation in the UK.
"We've seen its popularity continue to rise," says Dorothy.
The WI saw one its busiest years last year, when the organisations celebrated its centenary with a host of events, as well as an invitation to the Royal Garden Party at Buckingham Palace, where members, including Dorothy, rubbed shoulders with The Duchess of Cornwall.
"It was the icing on the cake of a wonderful year," smiles Dorothy.
And this year looks set to be busy too. Four new groups have opened their doors already in 2016, three of them in Sheffield, and Dorothy is certain there will be more.
"Anyone can start a group if they live in an area there isn't one already," says Dorothy, who works several hours a week overseeing the running of the South Yorkshire Federation, as well as running her own local WI group once a month.
As well as the local meetings, there are a variety of events throughout the year for all regional members.
And despite being a charity themselves, the WI makes it its mission to support other local charities, raising thousands of pounds every year for local hospices and women's refuge centres.
Visit South Yorkshire Federation of Women's Institute for details.
* WI members supported Tommies during the First World War, growing vegetables and preserve food to aid the nation on the home front.
* In 1941, the WI sparked a national debate about child evacuees, after publishing the results of a survey they'd carried out showing young evacuees living in urban areas of Britain were malnourished, unclean and in poor health. This debate led to the establishment of family allowances to help those in poverty.


burritos « The Sporkful - It's not for foodies, it's for eaters.
What Makes A Sandwich A Sandwich?
Is a buttered roll a sandwich? Is it still brunch if it's at 2 pm? Dan debates food and language with Peter Kim from the Museum of Food and Drink and Helen Zaltzman from The Allusionist.
Is a burrito better when its ingredients are mixed up before being rolled in the tortilla? What's the best way to eat the end cap? And if any flour tortilla shape were possible, what would be ideal?
Burritos and Sailboats Together — Finally!


Ancient Egypt Tours Representative will pick up you from your hotel in Dahab, transfer to Sharm Elshikh Airport, fly to Luxor, upon arrival Luxor airport you meet and assist by Ancient Egypt Tours representative. Start your private Luxor tour from Taba with your Egyptologist tour guide,Enjoy your private Day Tour in Luxor from Cairo, visit The East Bank of Luxor including Karnak Temple and Luxor Temple, enjoy the lunch in local restaurant, transfer to your hotel in Luxor, check in and overnight.
Breakfast at your hotel, enjoy day tour in Luxor and visit the West bank of Luxor, visit Valley of the kings you will enter three royal tombs except Tutankamoun tomb is an optional with extra fees, you will enjoy lunch during the tour. Then, proceed to Hatshepsut temple called Deir El-Bahari temple. After that, visit Colossi of Memnon statues, transfer to Luxor airport to catch your flight back to Taba, upon arrival Sharm Elshikh Airport, you meet and assist by Ancient Egypt Tours representative, transfer back to your hotel in Dahab.
We will star to enjoy an excursion to visit The East Bank of Luxor including, The Karnak Temple, the largest place of worship ever built. In ancient Egypt, the power of the god Amun of Thebes gradually increased during the early New Kingdom, and after the short persecution led by Akhenaten, it rose to its apex. In the reign of Ramesses III, more than two thirds of the property owned by the temples belonged to Amun, evidenced by the stupendous buildings at Karnak. Although badly ruined, no site in Egypt is more impressive than Karnak. It is the largest temple complex ever built by man, and represents the combined achievement of many generations of ancient builders. The Temple of Karnak is actually three main temples, smaller enclosed temples, and several outer temples located about three kilometers north of Luxor, Egypt situated on 100 ha (247 acres) of land. Karnak is actually the sites modern name. Its ancient name was Ipet-isut, meaning "The Most Select (or Sacred) of Places".
And then you will be accompanied by your tour guide to visit the majestic Luxor temple which was built by Amenhotep III and Ramses II for ritual and festivals and dedicated to the god Amun with some free time for shopping in Luxor.
From there will be driven to your hotel for check in, leisurely free time in Luxor and overnight in Luxor.
Early morning, enjoy a relaxing breakfast in your hotel in Luxor and then you will enjoy visiting the West Bank of The Nile River you will be visiting the two colossal statues of Amenhotep III (Colossi of Memnon) are the two massive stone statues of Pharaoh Amenhotep III. For 3,400 years they have sat in the Theban necropolis, across the River Nile from the city of Luxor. The original function of the Colossi was to stand guard at the entrance to Amenhotep's memorial temple or mortuary temple.
Queen Hatshepsut was the first great woman in recorded history: the forerunner of such figures as Cleopatra, Catherine the Great and Elizabeth I.The Mortuary Temple of Hatshepsut is the focal point of the Deir el-Bahri complex of mortuary temples and tombs located on the west bank of the Nile, opposite the city of Luxor. Hatshepsut was female pharoah. Her temple, This temple was built on three surfaces take the form of balconies, devoted primarily to the worship of the god Amun, and to perform funeral rites for the queen known as El Deir El Bahary, and then you will be transferred to Luxor domestic airport to fly back to Sharm Elshikh where you will be met by a company Representative and transferred by private air conditioned van class to your hotel in Dahab.
Return flight from Sharm, Luxor,Sharm.
Service of professional tour guide.
A bottle of water during your trip.
Accommodation in Luxor at 5* hotel.
Assistance of our personal during tours.
All transfers by air-conditioned mini-bus.
All services charges and taxes included.


text:
Agenus Announces Collaboration and License Agreement with Merck for Novel Checkpoint Antibody-Based Cancer Immunotherapies
(Ref: Business Wire)
Agenus
Agenus is eligible to receive ~$100 million in milestone payments as well as royalties on worldwide product sales
LEXINGTON, Mass.--(BUSINESS WIRE)-- Agenus Inc. (NASDAQ: AGEN) announced today that the company has entered into a collaboration and license agreement with Merck, known as MSD outside the United States and Canada, through a subsidiary, for the discovery and development of therapeutic antibodies to immune checkpoints for the treatment of cancer. Under the terms of the agreement, Agenus will discover and optimize fully human antibodies against two undisclosed Merck checkpoint targets using the 4-Antibody Retrocyte Display® platform. Merck will be responsible for clinical development and commercialization of candidates generated under the collaboration.
Under the terms of the agreement, Agenus is eligible to receive approximately $100 million in potential payments associated with the completion of certain clinical, regulatory and commercial milestones for two candidates from Merck. In addition, Agenus is eligible to receive royalty payments on worldwide product sales.
"We are delighted to be working with Merck, who is a leader in the rapidly developing immuno-oncology space," said Bob Stein, MD, PhD, Chief Scientific Officer of Agenus Inc. "We believe our Retrocyte Display technology has significant advantages for creation of high quality antibody development candidates. This collaboration broadens our efforts in immuno-oncology beyond our previously disclosed checkpoint programs with a world-class research and development partner."
"This collaboration with Agenus complements our active immuno-oncology discovery programs," said Dr. Eric Rubin, vice president clinical oncology, Merck Research Laboratories. "We look forward to working to advance these programs with the potential to address the unmet medical needs of people with cancer."
Agenus acquired 4-Antibody AG, a private European-based biopharmaceutical company in February 2014. The 4-Antibody assets include the Retrocyte Display technology platform for discovery and optimization of fully human antibodies against a wide array of molecular targets. Agenus has multiple preclinical checkpoint modulator programs in development including GITR and OX40 agonists and antagonists of TIM-3, LAG-3, PD-1 and CTLA-4. These programs are being pursued through a strategic collaboration with Ludwig Cancer Research.
About Checkpoint Modulators
Clinical data from studies employing monoclonal antibodies that bind to checkpoint molecules, such as cytotoxic T lymphocyte antigen-4 (CTLA-4) and programmed death receptor-1 (PD-1), have generated considerable excitement in the field of immuno-oncology. Checkpoints are employed by the body to prevent a runaway immune response, which can be debilitating or deadly. Unfortunately, these very same checkpoint mechanisms can also be used by cancer cells as a defense against immune attack. Antibodies that bind to PD-1 and CTLA-4 are designed to help immune cells overcome the checkpoint defenses of cancer cells. Other checkpoint proteins, such as GITR and OX40, are receptors found on T cells that stimulate immune function. Agenus and Ludwig Cancer Research are driving leading-edge programs to discover and develop fully human monoclonal antibodies that bind to key checkpoint proteins and activate or block their activities for use in cancer therapy.
About Agenus
Agenus is an immuno-oncology company developing a portfolio of checkpoint modulators (CPMs), heat shock protein vaccines and adjuvants. Agenus' checkpoint modulator programs target GITR, OX40, CTLA-4, LAG-3, TIM-3 and PD-1. The company's proprietary discovery engine Retrocyte Display® is used to generate fully human therapeutic antibody drug candidates. The Retrocyte Display platform uses a high-throughput approach incorporating IgG format human antibody libraries expressed in mammalian B-lineage cells. Agenus' heat shock protein vaccines for cancer and infectious disease are in Phase 2 studies. The company's QS-21 Stimulon® adjuvant platform is extensively partnered with GlaxoSmithKline and Janssen and includes several candidates in Phase 3 trials. Among Agenus and its partners, 22 programs are in clinical development. For more information, please visit www.agenusbio.com, or connect with the company on Facebook, LinkedIn, Twitter and Google+.
Retrocyte Display and QS-21 Stimulon are registered trademarks of Agenus and its subsidiaries.
Source: Agenus Inc.
Agenus Announces Lead Product Candidate Selection in its Collaboration with Merck
Merck Extends Immuno-Oncology Collaboration with Agenus
Amgen And Merck Announce Cancer Immunotherapy Collaboration For Patients With Non-Hodgkin Lymphoma
Incyte and Agenus Announce Global Alliance to Develop Novel Immuno-Oncology Antibodies
Incyte Announces Clinical Trial Agreement to Evaluate Combination of Two Novel Cancer Immunotherapies


text:
Ticket to write! Royal Mail releases 12 stamps to honour ex-Beatle's Sir Paul McCartney's career
Ticket to write! Royal Mail releases 12 stamps to honour ex-Beatle's Sir Paul McCartney's career Stamp set features a selection of eight LPs defining Sir Paul McCartney's career Photographs spanning three decades of Sir Paul in the recording studio Royal Mail collaborated
Prince Philip was helping write book in his final days about his sister's German hunting lodge home
Right up to the end of his life, the Duke of Edinburgh was working on a book about his family's ancestral home in Germany – a mark of enduring devotion to his European relatives Right up to the end of his life,
National Trust slammed for asking children to write poems lamenting British Empire
Chartwell, Kent Chartwell's land has history dating back to the 14th century and it is thought to have been built on as early as the 16th century, with Historic England noting that some of the Tudor brickwork is still visible on external
Business chiefs and MPs write letter to Boris Johnson urging him to speed up reopening our skies
Business leaders last night united with MPs to plead with the Prime Minister to resume foreign travel. They warned that more than a million jobs were at risk if Boris Johnson failed to get Britain flying again. In letter to the PM,
Acid-penned biographer Tom Bower 'is given six-figure deal to write biography of Meghan'
'This is the book Meghan will be dreading': Acid-penned biographer Tom Bower 'is given six-figure deal to write unauthorised biography of the Duchess' Bower renowned for unsparing portrayals of towering figures like Boris Johnson He'll embark on 12 months of meticulous research


Social media is becoming more and more important in business. It allows you to engage your target audience directly, as well as serving as a valuable SEO and lead generation tool. Site Evaluator analyzes your use of social media using a variety of metrics. Here's three ways on how to improve both your social media, and overall site score.
This has quickly become a must-have on any website. If you are using social networks to reach out to consumers you absolutely need to have buttons linking to your accounts on every page. Make it easy for users to see how to connect with you. Oftentimes, social media is the place where people get to see a different, more personable side of the company. If this means more sales leads, you need to make sure to link to these accounts every chance you get.
Engaging your audience does mean sharing content you have generated with your networks. It does not mean force feeding them your content. Don't spam your followers, and be sure your content is actually interesting to them. If they start sharing or re-tweeting your posts you are in good shape. Also, take any opportunity you get to share their content, as long as it is relevant to your business. People love attention on social media. Klout is a service that measure how people interact with your posts and you with theirs. The more back and forth there is, the higher your influence score will be.
Inbound links from social media networks are becoming increasingly important. This is a huge part of inbound marketing. Make sure these links are connected to great content that will help retain user traffic. Once you have a good content generation system in place, people will take notice, and actively search for your content on social networks. Great content means more followers, which means more traffic, and that means more sales opportunities.


Adrian A. Asli is an Associate in Cummings & Lockwood's Corporate and Finance Group. His practice focuses on representing financial institutions in secured lending and asset based finance transactions. Prior to joining Cummings & Lockwood, Adrian served as director of an investment management firm and as a managing associate and associate at international law firms in New York and Florida.


We held two cruises as part of both the Guitars In Bars section of the Adelaide Guitar Festival and Umbrella Winter City Sounds Festival. The cruises, Original Word and While My Guitar Gently Sleeps featured amazing local guitarists!
Nice Verdes are Sally and Jesse who have been performing since first meeting at a peace march in Vancouver in 2003. They have performed and toured Australia, Canada, New Zealand, Europe and Guatemala and have studied music and dance in Cuba, India, West Africa and Colombia, continually honing their craft.
Nice Verdes are always on some kind of adventure in search of new inspiration and music. They have caught numerous planes, boats, bicycles and hitchhiked to play festivals and shows around the world as well as swinging in a hammock on a boat down the Amazon, hiking up mountains in the Andes, living in a shack in West Africa with no electricity, dancing in the desert at a rain dance, seeing an Orisha ceremony in Cuba, bathing in ancient thermal baths in Budapest, sleeping under the stars in the middle of Australia, gardening on the slopes of the Mediterranean, swimming in the Ganges, planting palms in the jungles of Costa Rica and enjoying Tango in Argentina.
Nice Verdes has released two albums, 'succulence' in 2008 and 'brontosaurus' in 2014. Their music is uplifting and sunny; original indie world. Inspired by the music's of the world; Cuba, Colombia, Africa, Europe and Latin America; they play combinations of Cuban tres, accordions, ukulele, guitar, harmonica and vocals.
This cruise was catered by The Vegan Catering Company and you could dance the night away with the portable dance floor being set up by Luke Wilcox on the boat!
Reid Sampson entertained you with selections of Tommy Emmanuel, jazz standards and he made his guitar weep.
The sounds of the guitar are vast, intriguing and can be so beautiful. The guitar can take you places and times that may have not even been to. What is a campfire without a guitar being played, the mall without a guitar busker or a teen moment of either a girl or boy playing you a song they wrote for you on guitar? It is definitely time we paid homage to the guitar, and Reid Sampson is one of the best guitarists I know. Lose yourself in the melodies and drift away from reality for a while.


Stage II vapor recovery systems have been required at most Chicago area retail and commercial gasoline dispensing facilities (GDF) located in Cook, DuPage, Kane, Lake, McHenry, and Will counties, along with Oswego Township in Kendall County, and Goose Lake and Aux Sable Townships in Grundy County, since the mid-1990's. Recently, the U.S. Environmental Protection Agency (U.S. EPA) determined that onboard refueling vapor recovery technology is now present in enough motor vehicles such that the onboard vapor recovery systems on the vehicles can now replace the dispenser-based Stage II equipment. With this determination, the U.S. EPA is allowing states, including Illinois, to no longer require Stage II vapor recovery and to begin decommissioning the existing Stage II vapor recovery systems at affected facilities.
As a result of U.S. EPA's action, the Illinois EPA submitted proposed rule changes to the Stage II program this past summer to the Illinois Pollution Control Board (PCB). On December 19, 2013 the PCB adopted the rules to: (1) eliminate the Stage II equipment installation requirements for new GDFs; and (2) require existing retail and commercial GDFs that have Stage II systems to decommission the equipment by December 31, 2016. It is important to note that, while GDF owners or operators can now decommission their Stage II systems, the Stage II equipment and its related components must remain in good working order, with proper maintenance, and stay in service until the day that contractors arrive to decommission the equipment at the site.
At least ten days prior to the start of decommissioning activities at your facility, a Notice of Intent to Decommission Stage II Vapor Recovery Equipment form must be submitted to the Illinois EPA. The Stage II systems must be decommissioned using one or more contractors that have the appropriate licenses and registrations with the Office of the Illinois State Fire Marshal and the Illinois Department of Agriculture's Bureau of Weights & Measures. The necessary forms, general information on the GDF decommissioning and contractor requirements, and applicable rules can be found by clicking on the "Stage II Vapor Recovery Decommissioning" link (right sidebar) on the Illinois EPA's website at www.epa.state.il.us.
During the past several years, the Illinois Small Business Environmental Assistance Program (IL SBEAP) at the Illinois Department of Commerce & Economic Opportunity has provided recordkeeping calendars to assist stations in complying with the Stage II regulations. The current calendar ends in March 2014 and new calendars will not be issued due to the program changes. However, log pages will be available on the IL SBEAP's website at www.ienconnect.com/enviro for download and printing to assist GDFs with recordkeeping until the facility's Stage II equipment is decommissioned. The link is contained in the right sidebar.
For additional information about the recently adopted Stage II program changes and equipment decommissioning requirements, be sure to visit www.epa.state.il.us. For questions or information that is not available online, you can contact the Illinois EPA at epa.stage2@illinois.gov or call 217-557-1441. In addition, you may contact the Illinois Small Business Environmental Assistance Program at 800-252-3998.
We are pleased to announce that the Illinois Sustainable Technology Center (ISTC) is now accepting applications for the 2014 Illinois Governor's Sustainability Awards! This award, begun in 1987, is the nation's oldest continuing pollution prevention program and annually honors organizations and businesses that have made a commitment to the environment through outstanding and innovative sustainability practices.
The deadline for submitting your application is close of business May 22, 2014. Applications will only be accepted electronically. Details and application information can be found on our website.
The award ceremony will be held this fall in Chicago, and once again ISTC will host the Illinois Campus Sustainability Compact Awards Program in conjunction with the Governor's Sustainability Awards program. A technical symposium will take place prior to the awards ceremony, bringing together a forum for education and networking opportunities.
We encourage you to forward this announcement to colleagues that may also be interested in the program.
Contact, Debra Jacobson, Senior Operations Manager, djacobson@illinois.edu or John Mulrow, Business & Industrial Sustainability Specialist, jmulrow@illinois.edu with any questions you might have about the application process or awards program.
The U.S. Environmental Protection Agency (USEPA) is proposing standards for the amount of air pollution that can be emitted by new woodstoves and heaters, beginning in 2015. The agency's proposal would make the next generation of stoves and heaters an estimated 80 percent cleaner than those manufactured today, leading to important air quality and public health improvements in communities across the country. The proposal would affect a variety of wood heaters manufactured beginning in 2015 and will not affect heaters and stoves already in use in homes or currently for sale today.
Smoke from residential wood heaters, which are used around the clock in some communities, can increase toxic air pollution, volatile organic compounds, carbon monoxide and soot, also known as particle pollution, to levels that pose serious health concerns. Particle pollution is linked to a wide range of serious health effects, including heart attacks, strokes and asthma attacks. In some areas, residential wood smoke makes up a significant portion of the fine particle pollution problem. USEPA's proposal would work in concert with state and local programs to improve air quality in these communities.
The agency's proposal covers several types of new wood-fired heaters, including: woodstoves, fireplace inserts, indoor and outdoor wood boilers (also called hydronic heaters), forced air furnaces and masonry heaters. Many residential wood heaters already meet the first set of proposed standards, which would be phased in over five years to allow manufacturers time to adapt emission control technologies to their particular model lines. Today's proposal does not cover fireplaces, fire pits, pizza ovens, barbecues and chimineas.
When these standards are fully implemented, USEPA estimates that for every dollar spent to comply with these standards, the American public will see between $118 and $267 in health benefits. Consumers will also see a monetary benefit from efficiency improvements in the new woodstoves, which use less wood to heat homes. The total health and economic benefits of the proposed standards are estimated to be at $1.8 to $2.4 billion annually.
USEPA will accept written comments until May 5, 2014.
Online at: Regulations.gov: Follow the on-line instructions for submitting comments.
Fax: Fax your comments to: 202-566-9744.
Mail: Send your comments to: Air and Radiation Docket and Information Center, Environmental Protection Agency, Mail Code: 2822T, 1200 Pennsylvania Ave., NW, Washington, DC, 20460.
Hand Delivery or Courier: Deliver your comments to: USEPA Docket Center, Room 3334, 1301 Constitution Ave., NW, Washington, DC, 20460. Such deliveries are only accepted during the Docket's normal hours of operation, and special arrangements should be made for deliveries of boxed information.
For more information visit: http://www2.epa.gov/residential-wood-heaters.
The U.S. Environmental Protection Agency (USEPA) and U.S. Army Corps of Engineers (Army Corps) released a proposed rule to clarify protection under the Clean Water Act for streams and wetlands that form the foundation of the nation's water resources. The proposed rule will benefit businesses by increasing efficiency in determining coverage of the Clean Water Act. The agencies are launching a robust outreach effort over the next 90 days, holding discussions around the country and gathering input needed to shape a final rule.
The proposed rule clarifies protection for streams and wetlands. The proposed definitions of waters will apply to all Clean Water Act programs. It does not protect any new types of waters that have not historically been covered under the Clean Water Act and is consistent with the Supreme Court's more narrow reading of Clean Water Act jurisdiction.
Most seasonal and rain dependent streams are protected.
Wetlands near rivers and streams are protected.
Other types of waters may have more uncertain connections with downstream water and protection will be evaluated through a case specific analysis of whether the connection is or is not protecting similarly situated waters in certain geographic areas or adding to the categories of waters protected without case specific analysis.
The proposed rule preserves the Clean Water Act exemptions and exclusions for agriculture. Additionally, USEPA and the Army Corps have coordinated with the U.S. Department of Agriculture (USDA) to develop an interpretive rule to ensure that 53 specific conservation practices that protect or improve water quality will not be subject to Section 404 dredged or fill permitting requirements. The agencies will work together to implement these new exemptions and periodically review, and update USDA's Natural Resources Conservation Service conservation practice standards and activities that would qualify under the exemption. Any agriculture activity that does not result in the discharge of a pollutant to waters of the U.S. still does not require a permit.
On March 3, 2014 the United States Environmental Protection Agency (USEPA) finalized amendments to establish new tailpipe standards for the sum of non-methane organic gases (NMOG) and nitrogen oxides (NOX), presented as NMOG+NOX, and for particular matter (PM) that apply to all light-duty vehicles and some heavy-duty vehicles. Compared to current standards, the NMOG and NOX tailpipe standards for light-duty vehicles represent approximately an 80% reduction from today's fleet average and a 70% reduction in per-vehicle PM standards. Heavy-duty tailpipe standards represent about a 60% reduction in both fleet average NMOG+NOX and per-vehicle PM standards. USEPA also extended the regulatory useful life period during which the standards apply from 120,000 miles to 150,000 miles.
The tailpipe standards include different phase-in schedules that vary by vehicle class, but generally phase in between model years 2017 and 2025. In addition to the gradual phase-in schedules, several other provisions are designed to further ease manufacturers' paths to compliance with the stringent new standards. Depending on the standards and the vehicle class, these flexibility provisions include credits for early compliance and the ability to offset some higher-emitting vehicles with extra-clean models. USEPA included more lead time for small businesses and small volume manufactures as well as a hardship provision that allows for additional time to comply if a manufacturer cannot meet requirements after a good faith effort and would face severe economic hardship without the additional lead time.
PM Standards: The PM standards are expressed on a per-vehicle basis, meaning the standards apply to each vehicle separately (i.e., not as a fleet average). USEPA is setting PM standards that differ by vehicle class and test cycle.
Evaporative Emission Standards: USEPA is setting more stringent standards designed to eliminate fuel vapor-related evaporative emissions and improve durability. The evaporative emissions program represents about a 50 percent reduction from current standards and applies to all light-duty and onroad gasoline-powered heavy-duty vehicles. As with the tailpipe standards, the evaporative emissions standards include phase-in flexibilities, credit and allowance programs, and more lead time and a hardship provision for small businesses and small volume manufacturers. USEPA is also extending the regulatory useful life period during which the standards apply from 120,000 miles to 150,000 miles.
Fuel Standards: USEPA is finalizing gasoline sulfur reductions that are critical to enabling manufacturers to comply across the fleet with the stringent vehicle standards. The gasoline sulfur standards will also achieve significant immediate benefits by reducing emissions from existing vehicles. Under the final Tier 3 program, federal gasoline will be required to meet an annual average standard of 10 parts per million (ppm) of sulfur by January 1, 2017. USEPA is also finalizing standards that maintain the current 80 ppm refinery gate and 95 ppm downstream cap. The Tier 3 gasoline sulfur standards are similar to levels already being achieved in California, Europe, Japan, South Korea, and several other countries.
For the gasoline sulfur standards, USEPA is finalizing averaging, banking, and trading (ABT) program that allows refiners and importers to spread out their investments through an early credit program and rely on ongoing nationwide averaging to meet the 10 ppm sulfur standard. New to the final rule, USEPA is including the ability to carry over credits from Tier 2 to Tier 3 in the ABT program. USEPA is also finalizing a three-year delay for small refiners and small volume refineries processing 75,000 barrels of crude oil per day or less, as well as other flexibilities for refiners such as hardship provisions for extenuating circumstances.
Emissions Test Fuel: USEPA is updating the federal emissions test fuel to better match today's in-use gasoline and also to be forward-looking with respect to future ethanol and sulfur content. The new test fuel specifications apply to new vehicle certification, assembly line, and in-use testing. USEPA is transitioning to the new test fuel during the first few years that the Tier 3 tailpipe and evaporative standards are phasing in. Key changes include moving to a test fuel containing 10 percent ethanol by volume, lowering octane, and lowering the existing sulfur specification to be consistent with Tier 3 requirements. USEPA is also setting test fuel specifications for E85 for the first time.
This guide describes how local governments can lead by example and increase use of combined heat and power (CHP) in their facilities and throughout their communities. CHP, also known as cogeneration, refers to the simultaneous production of electricity and thermal energy from a single fuel source. This guide includes an overview of the benefits of CHP systems, costs, sources of funding, and case studies. The guide is designed to be used by staff at local energy or environment agencies, local code enforcement officials and city planners, city councils, and mayors or county executives. It also provides information useful for local government partners, such as local businesses, utilities, energy service companies, and non-profit organizations. Readers of the guide should come away with an understanding of options to improve energy efficiency using CHP, a clear idea of the steps and considerations involved in implementing CHP systems, and an awareness of expected investment and funding opportunities.
The Illinois Environmental Protection Agency will offer a course in the Evaluation of Visible Emissions during the week of April 14, 2014. The class will run from Tuesday, April 15 through Wednesday, April 16, 2014. Class begins at 9:00 AM each morning with registration beginning at approximately 8:00 AM; everyone must sign in one time only.
All newcomers attending for initial certification (not recertification) are expected to be present for a lecture session at 1:00 PM on Monday, April 14th; persons recertifying are welcome to attend the lecture as well. The lecture will include discussion of visible emissions and the finer points of reading opacity. The lecture will be held at the Ramada Limited Motel, 3281 Northfield Drive, Springfield, Illinois.
The class will be held at the Ramada Limited Motel, 3281 Northfield Drive, Springfield, Illinois. The telephone number is (217) 523-4000. A block of rooms has been set aside for the session, so please mention you are attending "Smoke School" when making your reservations. The Illinois Environmental Protection Agency does not charge a fee for this instruction. All participants must arrange for their own meals and lodging; however, all materials necessary for the course will be supplied with the exception of writing tools and a clipboard. Please be reminded this class is held outside, so dress appropriately and bring your own lawn chair.
Please fill out the registration form online at http://www.epa.state.il.us/air/smoke-school/registration.html prior to April 11, 2014. If you do not have access to the Internet please contact Linda Kulek at (217) 524-0546 to receive a registration form by mail. Remember to check the designated box for either certifying the first time or recertifying.
If you have any questions, I can be reached by e-mail Kevin.Mattison@illinois.gov or by phone (847) 294-4019.
Great Lakes Green Chemistry Conference- Innovating for Success in Green Chemistry April 1-2, 2014, Cleveland, OH. Click here for more information on the event.
Workshop-GreenScreen™Training April 3, 2014, Cleveland, OH. Hosted by US EPA Region 5 Great Lakes Restoration Initiative partners. The GreenScreen™ for Safer Chemicals is a comparative chemical hazard screening method developed by Clean Production Action to encourage the use of greener and safer chemicals. Click here for more information.


text:
Police: Thieves take $7,000 from Baja Ranch…
Police: Thieves take $7,000 from Baja Ranch Market safe
By Melissa Masatani | Melissa.Masatani@sgvn.com |
PUBLISHED: September 23, 2015 at 3:08 a.m. | UPDATED: August 28, 2017 at 3:09 a.m.
PASADENA >> Two suspects were being sought Tuesday after taking $7,000 from two safes at the Baja Ranch Market, officials said.
A market employee was cleaning around 3:49 a.m. Tuesday at the store in the 400 block of East Orange Grove Boulevard, Pasadena police Lt. John Luna said.
The employee, a 27-year-old Covina resident, heard an alarm go off and saw two masked suspects wearing dark clothes walk toward the manager's office, Luna said.
One of the suspects turned to look at the employee before continuing to walk toward the office, and the victim ran to the back of the store and hid in a freezer, where he called police, Luna said.
The suspects had fled the location before police arrived and officers discovered the suspects had kicked down the manager's door and taken approximately $7,000 in cash from two safes.
Melissa Masatani