text:
<?php

namespace TYPO3\CMS\Core\Context {

    use TYPO3\CMS\Core\Context\Exception\AspectPropertyNotFoundException;

    /**
     * Interface AspectInterface
     * Think of an aspect like a property bag
     */
    interface AspectInterface
    {
        /**
         * Get a property from an aspect
         *
         * @param string $name
         * @return mixed
         * @throws AspectPropertyNotFoundException
         */
        public function get(\string $name);
    }

    class Context implements SingletonInterface
    {
        /**
         * @var AspectInterface[]
         */
        protected $aspects = [];

        /**
         * Sets up the context with pre-defined aspects
         *
         * @param array|null $defaultAspects
         */
        public function __construct(array $defaultAspects = null)
        {
        }

        /**
         * Checks if an aspect exists in the context
         *
         * @param string $name
         * @return bool
         */
        public function hasAspect(string $name): bool
        {
            return isset($this->aspects[$name]);
        }

        /**
         * Sets an aspect, or overrides an existing aspect if an aspect is already set
         *
         * @param string $name
         * @param AspectInterface $aspect
         */
        public function setAspect(string $name, AspectInterface $aspect): void
        {
        }

        /**
         * Returns an aspect, if it is set
         *
         * @param string $name
         * @return AspectInterface
         * @throws AspectNotFoundException
         */
        public function getAspect(string $name): AspectInterface
        {
        }

        /**
         * Returns a propert yfrom the aspect, but only if the property is found.
         *
         * @param string $name
         * @param string $property
         * @param null $default
         * @return mixed|null
         * @throws AspectNotFoundException
         */
        public function getPropertyFromAspect(string $name, string $property, $default = null)
        {
        }
    }

    class UserAspect implements AspectInterface
    {
        /**
         * @var AbstractUserAuthentication
         */
        protected $user;

        /**
         * Alternative list of groups, usually useful for frontend logins with "magic" groups like "-1" and "-2"
         *
         * @var int[]
         */
        protected $groups;

        /**
         * @param AbstractUserAuthentication|null $user
         * @param array|null $alternativeGroups
         */
        public function __construct(AbstractUserAuthentication $user = null, array $alternativeGroups = null)
        {
        }

        /**
         * Fetch common information about the user
         *
         * @param string $name
         * @return int|bool|string|array
         * @throws AspectPropertyNotFoundException
         */
        public function get(string $name)
        {
        }

        /**
         * If a frontend user is checked, he/she also needs to have a group, otherwise it is only
         * checked if the frontend user has a uid > 0
         *
         * @return bool
         */
        public function isLoggedIn(): bool
        {
        }

        /**
         * Return the groups the user is a member of
         *
         * For Frontend Users there are two special groups:
         * "-1" = hide at login
         * "-2" = show at any login
         *
         * @return array
         */
        public function getGroupIds(): array
        {
        }

        /**
         * Get the name of all groups, used in Fluid's IfHasRole ViewHelper
         *
         * @return array
         */
        public function getGroupNames(): array
        {
        }

        /**
         * Checking if a user is logged in or a group constellation different from "0,-1"
         *
         * @return bool TRUE if either a login user is found OR if the group list is set to something else than '0,-1' (could be done even without a user being logged in!)
         */
        public function isUserOrGroupSet(): bool
        {
        }
    }
}


text:
template
=========

## Overview

Template is a fake project to demonstrate how to create a new code for the Azure IoT SDKs using the unit test suite together with mockable functions. This sample simulate a target module that calls functions in the callee module. The unit test will test the target functions emulating different behaviors for the callee mockable functions.
To complete this sample, this document describes the requirements for the target functions. If you are creating a new module for the SDK, it is mandatory that you create the requirements, each requirement must show up in the code, and must have, at least, one unity test to cover it.
Note that it is just a sample, so, this requirement does not contemplate all possible situations and we only have unit tests for the requirements that helped to demonstrate a test suite feature.

## References

Add any reference that can support this implementation here. For example, it the target implement a TLS protocol, it can have the follow references:

[TLS Protocol (RFC2246)](https://www.ietf.org/rfc/rfc2246.txt)

[TLS Protocol (generic information)](https://en.wikipedia.org/wiki/Transport_Layer_Security)

## Exposed API

**SRS_TEMPLATE_21_011: [** The target shall return the errors defined by the TARGET_RESULT in target.h. **]**
```c
#define TARGET_RESULT_VALUES         \
    TARGET_RESULT_OK,                \
    TARGET_RESULT_FAIL,              \
    TARGET_RESULT_OUT_OF_MEMORY
DEFINE_ENUM(TARGET_RESULT, TARGET_RESULT_VALUES);
```
**]**

**SRS_TEMPLATE_21_012: [** The target shall implement the APIs defined in target.h:
```c
TARGET_RESULT target_create(size_t size);
void target_destroy(void);
TARGET_RESULT target_foo(void);
```
**]**

###  target_create
```c
TARGET_RESULT target_create(size_t size);
```

**SRS_TEMPLATE_21_001: [** The target_create shall call callee_open to do stuff and allocate the memory. **]**
**SRS_TEMPLATE_21_002: [** If callee_open return error, the target_create shall return TARGET_RESULT_FAIL. **]**
**SRS_TEMPLATE_21_003: [** If there is no memory to control the target_create information, it shall return TARGET_RESULT_OUT_OF_MEMORY. **]**
**SRS_TEMPLATE_21_008: [** If callee_open got success, it shall return TARGET_RESULT_OK. **]**
**SRS_TEMPLATE_21_009: [** If callee_open is called but the connection is already created, it shall return TARGET_RESULT_OK. **]**

###  target_destroy
```c
void target_destroy(void);
```

**SRS_TEMPLATE_21_006: [** The target_destroy shall call callee_close to do stuff and free the memory. **]**
**SRS_TEMPLATE_21_007: [** If target_destroy is called but the connection is not created, the target_destroy shall not do anything. **]**

###  target_foo
```c
TARGET_RESULT target_foo(void);
```

**SRS_TEMPLATE_21_004: [** The target_foo shall do stuff calling callee_bar_1 and callee_bar_2. **]**
**SRS_TEMPLATE_21_005: [** If target_foo is called but the connection is not created, the target_foo shall return TARGET_RESULT_FAIL. **]**
**SRS_TEMPLATE_21_010: [** If target_foo cannot execute foo, the target_foo shall return TARGET_RESULT_FAIL. **]**

redpajama_set_name: RedPajamaGithub


text:
/*
  Import Dependencies
*/
import React from 'react';
import {render} from 'react-dom';
import {Provider} from 'react-redux';
import {Router, Route, IndexRoute} from 'react-router'
import 'babel-polyfill';

/* Import CSS */
//eslint-disable-next-line
import css from './styles/main.scss';

/*
  Import Components
*/
import App from './components/App';

/*
  Import Views
*/
import Home from "./views/Home";
import AuthView from "./views/AuthView";
import CreateJob from "./views/CreateJob";
import CreateLocation from "./views/CreateLocation";
import JobView from "./views/JobView";
import ProfileView from "./views/ProfileView";
import FourOFour from "./views/FourOFour";

/* Import our data store */
import store, {history} from './store';

function requireAuth() {
  return(nextState, replace) => {
    let currentState = store.getState();
    if(!currentState.user.isLoggedIn) {
      replace({ pathname: "/auth" });
    }
  };
}
/*
  Rendering
  This is where we hook up the Store with our actual component and the router
*/
render(
  <Provider store={store}>
    { /* Tell the Router to use our enhanced history */ }
    <Router history={history}>
      <Route path="/" component={App}>
        <IndexRoute component={Home} />
        <Route path="/auth" component={AuthView}></Route>
        <Route path="/createjob" component={CreateJob} onEnter={requireAuth()}></Route>
        <Route path="/createlocation" component={CreateLocation} onEnter={requireAuth()}></Route>
        <Route path="/job/:jobid" component={JobView} onEnter={requireAuth()}></Route>
        <Route path="/profile/:profileName" component={ProfileView} onEnter={requireAuth()}></Route>
      </Route>
      <Route path="*" component={FourOFour} />
    </Router>
  </Provider>,
  document.getElementById('root')
);


text:
'use strict';

const ruleTester = require('../utils/ruleTester');
const rule = require('../rules/ng-no-require-module-deps');

ruleTester.run('ng-no-require-module-deps', rule, {
  valid: [
    {
      code: `
        import { module } from 'angular';
        import FOO_MODULE from './foo';
        module('foo', [FOO_MODULE]);
      `,
    },
  ],

  invalid: [
    {
      errors: [
        {
          message: 'Prefer \'import ANGULARJS_LIBRARY from "angularjs-library"\' over \'require("angularjs-library")\'',
        },
      ],
      code: `
        import angular from 'angular';
        angular.module('foo', [ require('./foo') ]);
      `,
    },
  ],
});


text:
package com.jivesoftware.os.amza.api.partition;

/**
 *
 */
public enum Durability {
    ephemeral, fsync_never, fsync_async, fsync_always
}


text:
package cz.vsb.resbill.dto.customer;

import java.io.Serializable;

import cz.vsb.resbill.model.Customer;

public class CustomerDTO implements Serializable {

	private static final long serialVersionUID = -4649296501189503996L;

	private Integer customerId;

	private String name;

	public CustomerDTO(Customer customer) {
		fill(customer);
	}

	protected void fill(Customer customer) {
		if (customer != null) {
			this.customerId = customer.getId();
			this.name = customer.getName();
		}
	}

	public Integer getCustomerId() {
		return customerId;
	}

	public String getName() {
		return name;
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("CustomerDTO [");
		builder.append(super.toString());
		builder.append(", customerId=");
		builder.append(customerId);
		builder.append(", name=");
		builder.append(name);
		builder.append("]");
		return builder.toString();
	}

}


text:
import os, copy, zlib, fnmatch, re

import jasy.js.parse.Parser as Parser
import jasy.js.parse.ScopeScanner as ScopeScanner
import jasy.js.clean.DeadCode
import jasy.js.clean.Unused
import jasy.js.clean.Permutate
import jasy.js.optimize.Translation
import jasy.js.output.Optimization
import jasy.js.api.Data
import jasy.core.Permutation
import jasy.item.Abstract

from jasy.js.MetaData import MetaData
from jasy.js.output.Compressor import Compressor

from jasy import UserError
from jasy.js.util import *
import jasy.core.Console as Console

try:
    from pygments import highlight
    from pygments.lexers import JavascriptLexer
    from pygments.formatters import HtmlFormatter
except:
    highlight = None

aliases = {}

defaultOptimization = jasy.js.output.Optimization.Optimization("declarations", "blocks", "variables")
defaultPermutation = jasy.core.Permutation.getPermutation({"debug" : False})

def collectFields(node, keys=None):

    if keys is None:
        keys = set()

    # Always the first parameter
    # Supported calls: jasy.Env.isSet(key, expected?), jasy.Env.getValue(key), jasy.Env.select(key, map)
    calls = ("jasy.Env.isSet", "jasy.Env.getValue", "jasy.Env.select")
    if node.type == "dot" and node.parent.type == "call" and assembleDot(node) in calls:
        keys.add(node.parent[1][0].value)

    # Process children
    for child in reversed(node):
        if child != None:
            collectFields(child, keys)

    return keys

class ClassError(Exception):
    def __init__(self, inst, msg):
        self.__msg = msg
        self.__inst = inst

    def __str__(self):
        return "Error processing class %s: %s" % (self.__inst, self.__msg)

class ClassItem(jasy.item.Abstract.AbstractItem):

    kind = "class"

    def __getTree(self, context=None):

        field = "tree[%s]" % self.id
        tree = self.project.getCache().read(field, self.mtime)
        if not tree:
            Console.info("Processing class %s %s...", Console.colorize(self.id, "bold"), Console.colorize("[%s]" % context, "cyan"))

            Console.indent()
            tree = Parser.parse(self.getText(), self.id)
            ScopeScanner.scan(tree)
            Console.outdent()

            self.project.getCache().store(field, tree, self.mtime, True)

        return tree

    def __getOptimizedTree(self, permutation=None, context=None):
        """Returns an optimized tree with permutations applied"""

        field = "opt-tree[%s]-%s" % (self.id, permutation)
        tree = self.project.getCache().read(field, self.mtime)
        if not tree:
            tree = copy.deepcopy(self.__getTree("%s:plain" % context))

            # Logging
            msg = "Processing class %s" % Console.colorize(self.id, "bold")
            if permutation:
                msg += Console.colorize(" (%s)" % permutation, "grey")
            if context:
                msg += Console.colorize(" [%s]" % context, "cyan")

            Console.info("%s..." % msg)
            Console.indent()

            # Apply permutation
            if permutation:
                Console.debug("Patching tree with permutation: %s", permutation)
                Console.indent()
                jasy.js.clean.Permutate.patch(tree, permutation)
                Console.outdent()

            # Cleanups
            jasy.js.clean.DeadCode.cleanup(tree)
            ScopeScanner.scan(tree)
            jasy.js.clean.Unused.cleanup(tree)

            self.project.getCache().store(field, tree, self.mtime, True)
            Console.outdent()

        return tree

    def getDependencies(self, permutation=None, classes=None, warnings=True):
        """
        Returns a set of dependencies seen through the given list of known
        classes (ignoring all unknown items in original set). This method
        makes use of the meta data (see core/MetaData.py) and the variable data
        (see parse/ScopeData.py).
        """

        permutation = self.filterPermutation(permutation)

        meta = self.getMetaData(permutation)
        scope = self.getScopeData(permutation)

        result = set()

        # Manually defined names/classes
        for name in meta.requires:
            if name != self.id and name in classes and classes[name].kind == "class":
                result.add(classes[name])
            elif "*" in name:
                reobj = re.compile(fnmatch.translate(name))
                for className in classes:
                    if className != self.id:
                        if reobj.match(className):
                            result.add(classes[className])
            elif warnings:
                Console.warn("- Missing class (required): %s in %s", name, self.id)

        # Globally modified names (mostly relevant when working without namespaces)
        for name in scope.shared:
            if name != self.id and name in classes and classes[name].kind == "class":
                result.add(classes[name])

        # Add classes from detected package access
        for package in scope.packages:
            if package in aliases:
                className = aliases[package]
                if className in classes:
                    result.add(classes[className])
                    continue

            orig = package
            while True:
                if package == self.id:
                    break

                elif package in classes and classes[package].kind == "class":
                    aliases[orig] = package
                    result.add(classes[package])
                    break

                else:
                    pos = package.rfind(".")
                    if pos == -1:
                        break

                    package = package[0:pos]

        # Manually excluded names/classes
        for name in meta.optionals:
            if name != self.id and name in classes and classes[name].kind == "class":
                result.remove(classes[name])
            elif warnings:
                Console.warn("- Missing class (optional): %s in %s", name, self.id)

        return result

    def getScopeData(self, permutation=None):
        """
        Returns the top level scope object which contains information about the
        global variable and package usage/influence.
        """

        permutation = self.filterPermutation(permutation)

        field = "scope[%s]-%s" % (self.id, permutation)
        scope = self.project.getCache().read(field, self.mtime)
        if scope is None:
            scope = self.__getOptimizedTree(permutation, "scope").scope
            self.project.getCache().store(field, scope, self.mtime)

        return scope

    def getApi(self, highlight=True):
        field = "api[%s]-%s" % (self.id, highlight)
        apidata = self.project.getCache().read(field, self.mtime, inMemory=False)
        if apidata is None:
            apidata = jasy.js.api.Data.ApiData(self.id, highlight)

            tree = self.__getTree(context="api")
            Console.indent()
            apidata.scanTree(tree)
            Console.outdent()

            metaData = self.getMetaData()
            apidata.addAssets(metaData.assets)
            for require in metaData.requires:
                apidata.addUses(require)
            for optional in metaData.optionals:
                apidata.removeUses(optional)

            apidata.addSize(self.getSize())
            apidata.addFields(self.getFields())

            self.project.getCache().store(field, apidata, self.mtime, inMemory=False)

        return apidata

    def getHighlightedCode(self):
        field = "highlighted[%s]" % self.id
        source = self.project.getCache().read(field, self.mtime)
        if source is None:
            if highlight is None:
                raise UserError("Could not highlight JavaScript code! Please install Pygments.")

            lexer = JavascriptLexer(tabsize=2)
            formatter = HtmlFormatter(full=True, style="autumn", linenos="table", lineanchors="line")
            source = highlight(self.getText(), lexer, formatter)

            self.project.getCache().store(field, source, self.mtime)

        return source

    def getMetaData(self, permutation=None):
        permutation = self.filterPermutation(permutation)

        field = "meta[%s]-%s" % (self.id, permutation)
        meta = self.project.getCache().read(field, self.mtime)
        if meta is None:
            meta = MetaData(self.__getOptimizedTree(permutation, "meta"))
            self.project.getCache().store(field, meta, self.mtime)

        return meta

    def getFields(self):
        field = "fields[%s]" % (self.id)
        fields = self.project.getCache().read(field, self.mtime)
        if fields is None:
            fields = collectFields(self.__getTree(context="fields"))
            self.project.getCache().store(field, fields, self.mtime)

        return fields

    def getTranslations(self):
        field = "translations[%s]" % (self.id)
        result = self.project.getCache().read(field, self.mtime)
        if result is None:
            result = jasy.js.optimize.Translation.collectTranslations(self.__getTree(context="i18n"))
            self.project.getCache().store(field, result, self.mtime)

        return result

    def filterPermutation(self, permutation):
        if permutation:
            fields = self.getFields()
            if fields:
                return permutation.filter(fields)

        return None

    def getCompressed(self, permutation=None, translation=None, optimization=None, formatting=None, context="compressed"):
        permutation = self.filterPermutation(permutation)

        # Disable translation for caching / patching when not actually used
        if translation and not self.getTranslations():
            translation = None

        field = "compressed[%s]-%s-%s-%s-%s" % (self.id, permutation, translation, optimization, formatting)
        compressed = self.project.getCache().read(field, self.mtime)
        if compressed == None:
            tree = self.__getOptimizedTree(permutation, context)

            if translation or optimization:
                tree = copy.deepcopy(tree)

                if translation:
                    jasy.js.optimize.Translation.optimize(tree, translation)

                if optimization:
                    try:
                        optimization.apply(tree)
                    except jasy.js.output.Optimization.Error as error:
                        raise ClassError(self, "Could not compress class! %s" % error)

            compressed = Compressor(formatting).compress(tree)
            self.project.getCache().store(field, compressed, self.mtime)

        return compressed

    def getSize(self):
        field = "size[%s]" % self.id
        size = self.project.getCache().read(field, self.mtime)

        if size is None:
            compressed = self.getCompressed(context="size")
            optimized = self.getCompressed(permutation=defaultPermutation, optimization=defaultOptimization, context="size")
            zipped = zlib.compress(optimized.encode("utf-8"))

            size = {
                "compressed" : len(compressed),
                "optimized" : len(optimized),
                "zipped" : len(zipped)
            }

            self.project.getCache().store(field, size, self.mtime)

        return size


text:
namespace logging {

// Returns a UTF8 description from an OS X Status error.
std::string DescriptionFromOSStatus(OSStatus err);

class OSStatusLogMessage : public logging::LogMessage {
 public:
  OSStatusLogMessage(const char* file_path,
                     int line,
                     LogSeverity severity,
                     OSStatus status);
  ~OSStatusLogMessage();

 private:
  OSStatus status_;

  DISALLOW_COPY_AND_ASSIGN(OSStatusLogMessage);
};

}  // namespace logging

#define OSSTATUS_LOG_STREAM(severity, status) \
  COMPACT_GOOGLE_LOG_EX_##severity(OSStatusLogMessage, status).stream()

#define OSSTATUS_LOG(severity, status) \
  LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), LOG_IS_ON(severity))
#define OSSTATUS_LOG_IF(severity, condition, status) \
  LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), \
              LOG_IS_ON(severity) && (condition))

#define OSSTATUS_CHECK(condition, status)                       \
  LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), !(condition)) \
      << "Check failed: " #condition << ". "

#define OSSTATUS_DLOG(severity, status) \
  LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), DLOG_IS_ON(severity))
#define OSSTATUS_DLOG_IF(severity, condition, status) \
  LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status),  \
              DLOG_IS_ON(severity) && (condition))

#define OSSTATUS_DCHECK(condition, status)        \
  LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), \
              DCHECK_IS_ON() && !(condition))     \
      << "Check failed: " #condition << ". "

#endif  // BASE_MAC_MAC_LOGGING_H_


text:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package sba.gui.util;

/**
 *
 * @author Sergio Flores
 */
public interface DUtilBranchEntity extends DUtilBranch {

    public int[] getBranchEntityKey();
}


text:
'use strict';

import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import * as cp from 'child_process';
import { EventEmitter } from 'events';
import iconv = require('iconv-lite');
import * as filetype from 'file-type';
import { assign, uniqBy, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent } from './util';
import { CancellationToken } from 'vscode';

const readfile = denodeify<string>(fs.readFile);

export interface IGit {
	path: string;
	version: string;
}

export interface IFileStatus {
	x: string;
	y: string;
	path: string;
	rename?: string;
}

export interface Remote {
	name: string;
	url: string;
}

export interface Stash {
	index: number;
	description: string;
}

export enum RefType {
	Head,
	RemoteHead,
	Tag
}

export interface Ref {
	type: RefType;
	name?: string;
	commit?: string;
	remote?: string;
}

export interface Branch extends Ref {
	upstream?: string;
	ahead?: number;
	behind?: number;
}

function parseVersion(raw: string): string {
	return raw.replace(/^git version /, '');
}

function findSpecificGit(path: string, onLookup: (path: string) => void): Promise<IGit> {
	return new Promise<IGit>((c, e) => {
		onLookup(path);

		const buffers: Buffer[] = [];
		const child = cp.spawn(path, ['--version']);
		child.stdout.on('data', (b: Buffer) => buffers.push(b));
		child.on('error', cpErrorHandler(e));
		child.on('exit', code => code ? e(new Error('Not found')) : c({ path, version: parseVersion(Buffer.concat(buffers).toString('utf8').trim()) }));
	});
}

function findGitDarwin(onLookup: (path: string) => void): Promise<IGit> {
	return new Promise<IGit>((c, e) => {
		cp.exec('which git', (err, gitPathBuffer) => {
			if (err) {
				return e('git not found');
			}

			const path = gitPathBuffer.toString().replace(/^\s+|\s+$/g, '');

			function getVersion(path: string) {
				onLookup(path);

				// make sure git executes
				cp.exec('git --version', (err, stdout) => {

					if (err) {
						return e('git not found');
					}

					return c({ path, version: parseVersion(stdout.trim()) });
				});
			}

			if (path !== '/usr/bin/git') {
				return getVersion(path);
			}

			// must check if XCode is installed
			cp.exec('xcode-select -p', (err: any) => {
				if (err && err.code === 2) {
					// git is not installed, and launching /usr/bin/git
					// will prompt the user to install it

					return e('git not found');
				}

				getVersion(path);
			});
		});
	});
}

function findSystemGitWin32(base: string, onLookup: (path: string) => void): Promise<IGit> {
	if (!base) {
		return Promise.reject<IGit>('Not found');
	}

	return findSpecificGit(path.join(base, 'Git', 'cmd', 'git.exe'), onLookup);
}

function findGitWin32(onLookup: (path: string) => void): Promise<IGit> {
	return findSystemGitWin32(process.env['ProgramW6432'] as string, onLookup)
		.then(void 0, () => findSystemGitWin32(process.env['ProgramFiles(x86)'] as string, onLookup))
		.then(void 0, () => findSystemGitWin32(process.env['ProgramFiles'] as string, onLookup));
}

export function findGit(hint: string | undefined, onLookup: (path: string) => void): Promise<IGit> {
	const first = hint ? findSpecificGit(hint, onLookup) : Promise.reject<IGit>(null);

	return first
		.then(void 0, () => {
			switch (process.platform) {
				case 'darwin': return findGitDarwin(onLookup);
				case 'win32': return findGitWin32(onLookup);
				default: return findSpecificGit('git', onLookup);
			}
		})
		.then(null, () => Promise.reject(new Error('Git installation not found.')));
}

export interface IExecutionResult<T extends string | Buffer> {
	exitCode: number;
	stdout: T;
	stderr: string;
}

function cpErrorHandler(cb: (reason?: any) => void): (reason?: any) => void {
	return err => {
		if (/ENOENT/.test(err.message)) {
			err = new GitError({
				error: err,
				message: 'Failed to execute git (ENOENT)',
				gitErrorCode: GitErrorCodes.NotAGitRepository
			});
		}

		cb(err);
	};
}

export interface SpawnOptions extends cp.SpawnOptions {
	input?: string;
	encoding?: string;
	log?: boolean;
	cancellationToken?: CancellationToken;
}

async function exec(child: cp.ChildProcess, cancellationToken?: CancellationToken): Promise<IExecutionResult<Buffer>> {
	if (!child.stdout || !child.stderr) {
		throw new GitError({ message: 'Failed to get stdout or stderr from git process.' });
	}

	if (cancellationToken && cancellationToken.isCancellationRequested) {
		throw new GitError({ message: 'Cancelled' });
	}

	const disposables: IDisposable[] = [];

	const once = (ee: NodeJS.EventEmitter, name: string, fn: (...args: any[]) => void) => {
		ee.once(name, fn);
		disposables.push(toDisposable(() => ee.removeListener(name, fn)));
	};

	const on = (ee: NodeJS.EventEmitter, name: string, fn: (...args: any[]) => void) => {
		ee.on(name, fn);
		disposables.push(toDisposable(() => ee.removeListener(name, fn)));
	};

	let result = Promise.all<any>([
		new Promise<number>((c, e) => {
			once(child, 'error', cpErrorHandler(e));
			once(child, 'exit', c);
		}),
		new Promise<Buffer>(c => {
			const buffers: Buffer[] = [];
			on(child.stdout, 'data', (b: Buffer) => buffers.push(b));
			once(child.stdout, 'close', () => c(Buffer.concat(buffers)));
		}),
		new Promise<string>(c => {
			const buffers: Buffer[] = [];
			on(child.stderr, 'data', (b: Buffer) => buffers.push(b));
			once(child.stderr, 'close', () => c(Buffer.concat(buffers).toString('utf8')));
		})
	]) as Promise<[number, Buffer, string]>;

	if (cancellationToken) {
		const cancellationPromise = new Promise<[number, Buffer, string]>((_, e) => {
			onceEvent(cancellationToken.onCancellationRequested)(() => {
				try {
					child.kill();
				} catch (err) {
					// noop
				}

				e(new GitError({ message: 'Cancelled' }));
			});
		});

		result = Promise.race([result, cancellationPromise]);
	}

	try {
		const [exitCode, stdout, stderr] = await result;
		return { exitCode, stdout, stderr };
	} finally {
		dispose(disposables);
	}
}

export interface IGitErrorData {
	error?: Error;
	message?: string;
	stdout?: string;
	stderr?: string;
	exitCode?: number;
	gitErrorCode?: string;
	gitCommand?: string;
}

export class GitError {

	error?: Error;
	message: string;
	stdout?: string;
	stderr?: string;
	exitCode?: number;
	gitErrorCode?: string;
	gitCommand?: string;

	constructor(data: IGitErrorData) {
		if (data.error) {
			this.error = data.error;
			this.message = data.error.message;
		} else {
			this.error = void 0;
		}

		this.message = this.message || data.message || 'Git error';
		this.stdout = data.stdout;
		this.stderr = data.stderr;
		this.exitCode = data.exitCode;
		this.gitErrorCode = data.gitErrorCode;
		this.gitCommand = data.gitCommand;
	}

	toString(): string {
		let result = this.message + ' ' + JSON.stringify({
			exitCode: this.exitCode,
			gitErrorCode: this.gitErrorCode,
			gitCommand: this.gitCommand,
			stdout: this.stdout,
			stderr: this.stderr
		}, null, 2);

		if (this.error) {
			result += (<any>this.error).stack;
		}

		return result;
	}
}

export interface IGitOptions {
	gitPath: string;
	version: string;
	env?: any;
}

export const GitErrorCodes = {
	BadConfigFile: 'BadConfigFile',
	AuthenticationFailed: 'AuthenticationFailed',
	NoUserNameConfigured: 'NoUserNameConfigured',
	NoUserEmailConfigured: 'NoUserEmailConfigured',
	NoRemoteRepositorySpecified: 'NoRemoteRepositorySpecified',
	NotAGitRepository: 'NotAGitRepository',
	NotAtRepositoryRoot: 'NotAtRepositoryRoot',
	Conflict: 'Conflict',
	UnmergedChanges: 'UnmergedChanges',
	PushRejected: 'PushRejected',
	RemoteConnectionError: 'RemoteConnectionError',
	DirtyWorkTree: 'DirtyWorkTree',
	CantOpenResource: 'CantOpenResource',
	GitNotFound: 'GitNotFound',
	CantCreatePipe: 'CantCreatePipe',
	CantAccessRemote: 'CantAccessRemote',
	RepositoryNotFound: 'RepositoryNotFound',
	RepositoryIsLocked: 'RepositoryIsLocked',
	BranchNotFullyMerged: 'BranchNotFullyMerged',
	NoRemoteReference: 'NoRemoteReference',
	InvalidBranchName: 'InvalidBranchName',
	BranchAlreadyExists: 'BranchAlreadyExists',
	NoLocalChanges: 'NoLocalChanges',
	NoStashFound: 'NoStashFound',
	LocalChangesOverwritten: 'LocalChangesOverwritten'
};

function getGitErrorCode(stderr: string): string | undefined {
	if (/Another git process seems to be running in this repository|If no other git process is currently running/.test(stderr)) {
		return GitErrorCodes.RepositoryIsLocked;
	} else if (/Authentication failed/.test(stderr)) {
		return GitErrorCodes.AuthenticationFailed;
	} else if (/Not a git repository/.test(stderr)) {
		return GitErrorCodes.NotAGitRepository;
	} else if (/bad config file/.test(stderr)) {
		return GitErrorCodes.BadConfigFile;
	} else if (/cannot make pipe for command substitution|cannot create standard input pipe/.test(stderr)) {
		return GitErrorCodes.CantCreatePipe;
	} else if (/Repository not found/.test(stderr)) {
		return GitErrorCodes.RepositoryNotFound;
	} else if (/unable to access/.test(stderr)) {
		return GitErrorCodes.CantAccessRemote;
	} else if (/branch '.+' is not fully merged/.test(stderr)) {
		return GitErrorCodes.BranchNotFullyMerged;
	} else if (/Couldn\'t find remote ref/.test(stderr)) {
		return GitErrorCodes.NoRemoteReference;
	} else if (/A branch named '.+' already exists/.test(stderr)) {
		return GitErrorCodes.BranchAlreadyExists;
	} else if (/'.+' is not a valid branch name/.test(stderr)) {
		return GitErrorCodes.InvalidBranchName;
	}

	return void 0;
}

export class Git {

	private gitPath: string;
	private version: string;
	private env: any;

	private _onOutput = new EventEmitter();
	get onOutput(): EventEmitter { return this._onOutput; }

	constructor(options: IGitOptions) {
		this.gitPath = options.gitPath;
		this.version = options.version;
		this.env = options.env || {};
	}

	open(repository: string): Repository {
		return new Repository(this, repository);
	}

	async init(repository: string): Promise<void> {
		await this.exec(repository, ['init']);
		return;
	}

	async clone(url: string, parentPath: string, cancellationToken?: CancellationToken): Promise<string> {
		const folderName = decodeURI(url).replace(/^.*\//, '').replace(/\.git$/, '') || 'repository';
		const folderPath = path.join(parentPath, folderName);

		await mkdirp(parentPath);
		await this.exec(parentPath, ['clone', url, folderPath], { cancellationToken });
		return folderPath;
	}

	async getRepositoryRoot(repositoryPath: string): Promise<string> {
		const result = await this.exec(repositoryPath, ['rev-parse', '--show-toplevel']);
		return path.normalize(result.stdout.trim());
	}

	async exec(cwd: string, args: string[], options: SpawnOptions = {}): Promise<IExecutionResult<string>> {
		options = assign({ cwd }, options || {});
		return await this._exec(args, options);
	}

	stream(cwd: string, args: string[], options: SpawnOptions = {}): cp.ChildProcess {
		options = assign({ cwd }, options || {});
		return this.spawn(args, options);
	}

	private async _exec(args: string[], options: SpawnOptions = {}): Promise<IExecutionResult<string>> {
		const child = this.spawn(args, options);

		if (options.input) {
			child.stdin.end(options.input, 'utf8');
		}

		const bufferResult = await exec(child, options.cancellationToken);

		if (options.log !== false && bufferResult.stderr.length > 0) {
			this.log(`${bufferResult.stderr}\n`);
		}

		let encoding = options.encoding || 'utf8';
		encoding = iconv.encodingExists(encoding) ? encoding : 'utf8';

		const result: IExecutionResult<string> = {
			exitCode: bufferResult.exitCode,
			stdout: iconv.decode(bufferResult.stdout, encoding),
			stderr: bufferResult.stderr
		};

		if (bufferResult.exitCode) {
			return Promise.reject<IExecutionResult<string>>(new GitError({
				message: 'Failed to execute git',
				stdout: result.stdout,
				stderr: result.stderr,
				exitCode: result.exitCode,
				gitErrorCode: getGitErrorCode(result.stderr),
				gitCommand: args[0]
			}));
		}

		return result;
	}

	spawn(args: string[], options: SpawnOptions = {}): cp.ChildProcess {
		if (!this.gitPath) {
			throw new Error('git could not be found in the system.');
		}

		if (!options) {
			options = {};
		}

		if (!options.stdio && !options.input) {
			options.stdio = ['ignore', null, null]; // Unless provided, ignore stdin and leave default streams for stdout and stderr
		}

		options.env = assign({}, process.env, this.env, options.env || {}, {
			VSCODE_GIT_COMMAND: args[0],
			LC_ALL: 'en_US.UTF-8',
			LANG: 'en_US.UTF-8'
		});

		if (options.log !== false) {
			this.log(`git ${args.join(' ')}\n`);
		}

		return cp.spawn(this.gitPath, args, options);
	}

	private log(output: string): void {
		this._onOutput.emit('log', output);
	}
}

export interface Commit {
	hash: string;
	message: string;
}

export class GitStatusParser {

	private lastRaw = '';
	private result: IFileStatus[] = [];

	get status(): IFileStatus[] {
		return this.result;
	}

	update(raw: string): void {
		let i = 0;
		let nextI: number | undefined;

		raw = this.lastRaw + raw;

		while ((nextI = this.parseEntry(raw, i)) !== undefined) {
			i = nextI;
		}

		this.lastRaw = raw.substr(i);
	}

	private parseEntry(raw: string, i: number): number | undefined {
		if (i + 4 >= raw.length) {
			return;
		}

		let lastIndex: number;
		const entry: IFileStatus = {
			x: raw.charAt(i++),
			y: raw.charAt(i++),
			rename: undefined,
			path: ''
		};

		// space
		i++;

		if (entry.x === 'R' || entry.x === 'C') {
			lastIndex = raw.indexOf('\0', i);

			if (lastIndex === -1) {
				return;
			}

			entry.rename = raw.substring(i, lastIndex);
			i = lastIndex + 1;
		}

		lastIndex = raw.indexOf('\0', i);

		if (lastIndex === -1) {
			return;
		}

		entry.path = raw.substring(i, lastIndex);

		// If path ends with slash, it must be a nested git repo
		if (entry.path[entry.path.length - 1] !== '/') {
			this.result.push(entry);
		}

		return lastIndex + 1;
	}
}

export class Repository {

	constructor(
		private _git: Git,
		private repositoryRoot: string
	) { }

	get git(): Git {
		return this._git;
	}

	get root(): string {
		return this.repositoryRoot;
	}

	// TODO@Joao: rename to exec
	async run(args: string[], options: SpawnOptions = {}): Promise<IExecutionResult<string>> {
		return await this.git.exec(this.repositoryRoot, args, options);
	}

	stream(args: string[], options: SpawnOptions = {}): cp.ChildProcess {
		return this.git.stream(this.repositoryRoot, args, options);
	}

	spawn(args: string[], options: SpawnOptions = {}): cp.ChildProcess {
		return this.git.spawn(args, options);
	}

	async config(scope: string, key: string, value: any, options: SpawnOptions): Promise<string> {
		const args = ['config'];

		if (scope) {
			args.push('--' + scope);
		}

		args.push(key);

		if (value) {
			args.push(value);
		}

		const result = await this.run(args, options);
		return result.stdout;
	}

	async bufferString(object: string, encoding: string = 'utf8'): Promise<string> {
		const stdout = await this.buffer(object);
		return iconv.decode(stdout, iconv.encodingExists(encoding) ? encoding : 'utf8');
	}

	async buffer(object: string): Promise<Buffer> {
		const child = this.stream(['show', object]);

		if (!child.stdout) {
			return Promise.reject<Buffer>('Can\'t open file from git');
		}

		const { exitCode, stdout } = await exec(child);

		if (exitCode) {
			return Promise.reject<Buffer>(new GitError({
				message: 'Could not show object.',
				exitCode
			}));
		}

		return stdout;
	}

	async lstree(treeish: string, path: string): Promise<{ mode: number, object: string, size: number }> {
		if (!treeish) { // index
			const { stdout } = await this.run(['ls-files', '--stage', '--', path]);

			const match = /^(\d+)\s+([0-9a-f]{40})\s+(\d+)/.exec(stdout);

			if (!match) {
				throw new GitError({ message: 'Error running ls-files' });
			}

			const [, mode, object] = match;
			const catFile = await this.run(['cat-file', '-s', object]);
			const size = parseInt(catFile.stdout);

			return { mode: parseInt(mode), object, size };
		}

		const { stdout } = await this.run(['ls-tree', '-l', treeish, '--', path]);

		const match = /^(\d+)\s+(\w+)\s+([0-9a-f]{40})\s+(\d+)/.exec(stdout);

		if (!match) {
			throw new GitError({ message: 'Error running ls-tree' });
		}

		const [, mode, , object, size] = match;
		return { mode: parseInt(mode), object, size: parseInt(size) };
	}

	async detectObjectType(object: string): Promise<{ mimetype: string, encoding?: string }> {
		const child = await this.stream(['show', object]);
		const buffer = await readBytes(child.stdout, 4100);

		try {
			child.kill();
		} catch (err) {
			// noop
		}

		const encoding = detectUnicodeEncoding(buffer);
		let isText = true;

		if (encoding !== Encoding.UTF16be && encoding !== Encoding.UTF16le) {
			for (let i = 0; i < buffer.length; i++) {
				if (buffer.readInt8(i) === 0) {
					isText = false;
					break;
				}
			}
		}

		if (!isText) {
			const result = filetype(buffer);

			if (!result) {
				return { mimetype: 'application/octet-stream' };
			} else {
				return { mimetype: result.mime };
			}
		}

		if (encoding) {
			return { mimetype: 'text/plain', encoding };
		} else {
			// TODO@JOAO: read the setting OUTSIDE!
			return { mimetype: 'text/plain' };
		}
	}

	async add(paths: string[]): Promise<void> {
		const args = ['add', '-A', '--'];

		if (paths && paths.length) {
			args.push.apply(args, paths);
		} else {
			args.push('.');
		}

		await this.run(args);
	}

	async stage(path: string, data: string): Promise<void> {
		const child = this.stream(['hash-object', '--stdin', '-w', '--path', path], { stdio: [null, null, null] });
		child.stdin.end(data, 'utf8');

		const { exitCode, stdout } = await exec(child);
		const hash = stdout.toString('utf8');

		if (exitCode) {
			throw new GitError({
				message: 'Could not hash object.',
				exitCode: exitCode
			});
		}

		await this.run(['update-index', '--cacheinfo', '100644', hash, path]);
	}

	async checkout(treeish: string, paths: string[]): Promise<void> {
		const args = ['checkout', '-q'];

		if (treeish) {
			args.push(treeish);
		}

		if (paths && paths.length) {
			args.push('--');
			args.push.apply(args, paths);
		}

		try {
			await this.run(args);
		} catch (err) {
			if (/Please, commit your changes or stash them/.test(err.stderr || '')) {
				err.gitErrorCode = GitErrorCodes.DirtyWorkTree;
			}

			throw err;
		}
	}

	async commit(message: string, opts: { all?: boolean, amend?: boolean, signoff?: boolean, signCommit?: boolean } = Object.create(null)): Promise<void> {
		const args = ['commit', '--quiet', '--allow-empty-message', '--file', '-'];

		if (opts.all) {
			args.push('--all');
		}

		if (opts.amend) {
			args.push('--amend');
		}

		if (opts.signoff) {
			args.push('--signoff');
		}

		if (opts.signCommit) {
			args.push('-S');
		}

		try {
			await this.run(args, { input: message || '' });
		} catch (commitErr) {
			if (/not possible because you have unmerged files/.test(commitErr.stderr || '')) {
				commitErr.gitErrorCode = GitErrorCodes.UnmergedChanges;
				throw commitErr;
			}

			try {
				await this.run(['config', '--get-all', 'user.name']);
			} catch (err) {
				err.gitErrorCode = GitErrorCodes.NoUserNameConfigured;
				throw err;
			}

			try {
				await this.run(['config', '--get-all', 'user.email']);
			} catch (err) {
				err.gitErrorCode = GitErrorCodes.NoUserEmailConfigured;
				throw err;
			}

			throw commitErr;
		}
	}

	async branch(name: string, checkout: boolean): Promise<void> {
		const args = checkout ? ['checkout', '-q', '-b', name] : ['branch', '-q', name];
		await this.run(args);
	}

	async deleteBranch(name: string, force?: boolean): Promise<void> {
		const args = ['branch', force ? '-D' : '-d', name];
		await this.run(args);
	}

	async renameBranch(name: string): Promise<void> {
		const args = ['branch', '-m', name];
		await this.run(args);
	}

	async merge(ref: string): Promise<void> {
		const args = ['merge', ref];

		try {
			await this.run(args);
		} catch (err) {
			if (/^CONFLICT /m.test(err.stdout || '')) {
				err.gitErrorCode = GitErrorCodes.Conflict;
			}

			throw err;
		}
	}

	async tag(name: string, message?: string): Promise<void> {
		let args = ['tag'];

		if (message) {
			args = [...args, '-a', name, '-m', message];
		} else {
			args = [...args, name];
		}

		await this.run(args);
	}

	async clean(paths: string[]): Promise<void> {
		const pathsByGroup = groupBy(paths, p => path.dirname(p));
		const groups = Object.keys(pathsByGroup).map(k => pathsByGroup[k]);
		const tasks = groups.map(paths => () => this.run(['clean', '-f', '-q', '--'].concat(paths)));

		for (let task of tasks) {
			await task();
		}
	}

	async undo(): Promise<void> {
		await this.run(['clean', '-fd']);

		try {
			await this.run(['checkout', '--', '.']);
		} catch (err) {
			if (/did not match any file\(s\) known to git\./.test(err.stderr || '')) {
				return;
			}

			throw err;
		}
	}

	async reset(treeish: string, hard: boolean = false): Promise<void> {
		const args = ['reset'];

		if (hard) {
			args.push('--hard');
		}

		args.push(treeish);

		await this.run(args);
	}

	async revert(treeish: string, paths: string[]): Promise<void> {
		const result = await this.run(['branch']);
		let args: string[];

		// In case there are no branches, we must use rm --cached
		if (!result.stdout) {
			args = ['rm', '--cached', '-r', '--'];
		} else {
			args = ['reset', '-q', treeish, '--'];
		}

		if (paths && paths.length) {
			args.push.apply(args, paths);
		} else {
			args.push('.');
		}

		try {
			await this.run(args);
		} catch (err) {
			// In case there are merge conflicts to be resolved, git reset will output
			// some "needs merge" data. We try to get around that.
			if (/([^:]+: needs merge\n)+/m.test(err.stdout || '')) {
				return;
			}

			throw err;
		}
	}

	async fetch(): Promise<void> {
		try {
			await this.run(['fetch']);
		} catch (err) {
			if (/No remote repository specified\./.test(err.stderr || '')) {
				err.gitErrorCode = GitErrorCodes.NoRemoteRepositorySpecified;
			} else if (/Could not read from remote repository/.test(err.stderr || '')) {
				err.gitErrorCode = GitErrorCodes.RemoteConnectionError;
			}

			throw err;
		}
	}

	async pull(rebase?: boolean, remote?: string, branch?: string): Promise<void> {
		const args = ['pull'];

		if (rebase) {
			args.push('-r');
		}

		if (remote && branch) {
			args.push(remote);
			args.push(branch);
		}

		try {
			await this.run(args);
		} catch (err) {
			if (/^CONFLICT \([^)]+\): \b/m.test(err.stdout || '')) {
				err.gitErrorCode = GitErrorCodes.Conflict;
			} else if (/Please tell me who you are\./.test(err.stderr || '')) {
				err.gitErrorCode = GitErrorCodes.NoUserNameConfigured;
			} else if (/Could not read from remote repository/.test(err.stderr || '')) {
				err.gitErrorCode = GitErrorCodes.RemoteConnectionError;
			} else if (/Pull is not possible because you have unmerged files|Cannot pull with rebase: You have unstaged changes|Your local changes to the following files would be overwritten|Please, commit your changes before you can merge/.test(err.stderr)) {
				err.gitErrorCode = GitErrorCodes.DirtyWorkTree;
			}

			throw err;
		}
	}

	async push(remote?: string, name?: string, setUpstream: boolean = false, tags = false): Promise<void> {
		const args = ['push'];

		if (setUpstream) {
			args.push('-u');
		}

		if (tags) {
			args.push('--tags');
		}

		if (remote) {
			args.push(remote);
		}

		if (name) {
			args.push(name);
		}

		try {
			await this.run(args);
		} catch (err) {
			if (/^error: failed to push some refs to\b/m.test(err.stderr || '')) {
				err.gitErrorCode = GitErrorCodes.PushRejected;
			} else if (/Could not read from remote repository/.test(err.stderr || '')) {
				err.gitErrorCode = GitErrorCodes.RemoteConnectionError;
			}

			throw err;
		}
	}

	async createStash(message?: string, includeUntracked?: boolean): Promise<void> {
		try {
			const args = ['stash', 'save'];

			if (includeUntracked) {
				args.push('-u');
			}

			if (message) {
				args.push('--', message);
			}

			await this.run(args);
		} catch (err) {
			if (/No local changes to save/.test(err.stderr || '')) {
				err.gitErrorCode = GitErrorCodes.NoLocalChanges;
			}

			throw err;
		}
	}

	async popStash(index?: number): Promise<void> {
		try {
			const args = ['stash', 'pop'];

			if (typeof index === 'string') {
				args.push(`stash@{${index}}`);
			}

			await this.run(args);
		} catch (err) {
			if (/No stash found/.test(err.stderr || '')) {
				err.gitErrorCode = GitErrorCodes.NoStashFound;
			} else if (/error: Your local changes to the following files would be overwritten/.test(err.stderr || '')) {
				err.gitErrorCode = GitErrorCodes.LocalChangesOverwritten;
			}

			throw err;
		}
	}

	getStatus(limit = 5000): Promise<{ status: IFileStatus[]; didHitLimit: boolean; }> {
		return new Promise<{ status: IFileStatus[]; didHitLimit: boolean; }>((c, e) => {
			const parser = new GitStatusParser();
			const env = { GIT_OPTIONAL_LOCKS: '0' };
			const child = this.stream(['status', '-z', '-u'], { env });

			const onExit = (exitCode: number) => {
				if (exitCode !== 0) {
					const stderr = stderrData.join('');
					return e(new GitError({
						message: 'Failed to execute git',
						stderr,
						exitCode,
						gitErrorCode: getGitErrorCode(stderr),
						gitCommand: 'status'
					}));
				}

				c({ status: parser.status, didHitLimit: false });
			};

			const onStdoutData = (raw: string) => {
				parser.update(raw);

				if (parser.status.length > 5000) {
					child.removeListener('exit', onExit);
					child.stdout.removeListener('data', onStdoutData);
					child.kill();

					c({ status: parser.status.slice(0, 5000), didHitLimit: true });
				}
			};

			child.stdout.setEncoding('utf8');
			child.stdout.on('data', onStdoutData);

			const stderrData: string[] = [];
			child.stderr.setEncoding('utf8');
			child.stderr.on('data', raw => stderrData.push(raw as string));

			child.on('error', cpErrorHandler(e));
			child.on('exit', onExit);
		});
	}

	async getHEAD(): Promise<Ref> {
		try {
			const result = await this.run(['symbolic-ref', '--short', 'HEAD']);

			if (!result.stdout) {
				throw new Error('Not in a branch');
			}

			return { name: result.stdout.trim(), commit: void 0, type: RefType.Head };
		} catch (err) {
			const result = await this.run(['rev-parse', 'HEAD']);

			if (!result.stdout) {
				throw new Error('Error parsing HEAD');
			}

			return { name: void 0, commit: result.stdout.trim(), type: RefType.Head };
		}
	}

	async getRefs(): Promise<Ref[]> {
		const result = await this.run(['for-each-ref', '--format', '%(refname) %(objectname)']);

		const fn = (line: string): Ref | null => {
			let match: RegExpExecArray | null;

			if (match = /^refs\/heads\/([^ ]+) ([0-9a-f]{40})$/.exec(line)) {
				return { name: match[1], commit: match[2], type: RefType.Head };
			} else if (match = /^refs\/remotes\/([^/]+)\/([^ ]+) ([0-9a-f]{40})$/.exec(line)) {
				return { name: `${match[1]}/${match[2]}`, commit: match[3], type: RefType.RemoteHead, remote: match[1] };
			} else if (match = /^refs\/tags\/([^ ]+) ([0-9a-f]{40})$/.exec(line)) {
				return { name: match[1], commit: match[2], type: RefType.Tag };
			}

			return null;
		};

		return result.stdout.trim().split('\n')
			.filter(line => !!line)
			.map(fn)
			.filter(ref => !!ref) as Ref[];
	}

	async getStashes(): Promise<Stash[]> {
		const result = await this.run(['stash', 'list']);
		const regex = /^stash@{(\d+)}:(.+)$/;
		const rawStashes = result.stdout.trim().split('\n')
			.filter(b => !!b)
			.map(line => regex.exec(line) as RegExpExecArray)
			.filter(g => !!g)
			.map(([, index, description]: RegExpExecArray) => ({ index: parseInt(index), description }));

		return rawStashes;
	}

	async getRemotes(): Promise<Remote[]> {
		const result = await this.run(['remote', '--verbose']);
		const regex = /^([^\s]+)\s+([^\s]+)\s/;
		const rawRemotes = result.stdout.trim().split('\n')
			.filter(b => !!b)
			.map(line => regex.exec(line) as RegExpExecArray)
			.filter(g => !!g)
			.map((groups: RegExpExecArray) => ({ name: groups[1], url: groups[2] }));

		return uniqBy(rawRemotes, remote => remote.name);
	}

	async getBranch(name: string): Promise<Branch> {
		if (name === 'HEAD') {
			return this.getHEAD();
		}

		const result = await this.run(['rev-parse', name]);

		if (!result.stdout) {
			return Promise.reject<Branch>(new Error('No such branch'));
		}

		const commit = result.stdout.trim();

		try {
			const res2 = await this.run(['rev-parse', '--symbolic-full-name', '--abbrev-ref', name + '@{u}']);
			const upstream = res2.stdout.trim();

			const res3 = await this.run(['rev-list', '--left-right', name + '...' + upstream]);

			let ahead = 0, behind = 0;
			let i = 0;

			while (i < res3.stdout.length) {
				switch (res3.stdout.charAt(i)) {
					case '<': ahead++; break;
					case '>': behind++; break;
					default: i++; break;
				}

				while (res3.stdout.charAt(i++) !== '\n') { /* no-op */ }
			}

			return { name, type: RefType.Head, commit, upstream, ahead, behind };
		} catch (err) {
			return { name, type: RefType.Head, commit };
		}
	}

	async getCommitTemplate(): Promise<string> {
		try {
			const result = await this.run(['config', '--get', 'commit.template']);

			if (!result.stdout) {
				return '';
			}

			// https://github.com/git/git/blob/3a0f269e7c82aa3a87323cb7ae04ac5f129f036b/path.c#L612
			const homedir = os.homedir();
			let templatePath = result.stdout.trim()
				.replace(/^~([^\/]*)\//, (_, user) => `${user ? path.join(path.dirname(homedir), user) : homedir}/`);

			if (!path.isAbsolute(templatePath)) {
				templatePath = path.join(this.repositoryRoot, templatePath);
			}

			const raw = await readfile(templatePath, 'utf8');
			return raw.replace(/^\s*#.*$\n?/gm, '').trim();

		} catch (err) {
			return '';
		}
	}

	async getCommit(ref: string): Promise<Commit> {
		const result = await this.run(['show', '-s', '--format=%H\n%B', ref]);
		const match = /^([0-9a-f]{40})\n([^]*)$/m.exec(result.stdout.trim());

		if (!match) {
			return Promise.reject<Commit>('bad commit format');
		}

		return { hash: match[1], message: match[2] };
	}
}


text:
</div>
                </div>
            </div>
        </div>
        <script src="<?=base_url()?>application/asset/jquery/jquery-3.2.1.js" integrity="sha256-DZAnKJ/6XZ9si04Hgrsxu/8s717jcIzLy3oi35EouyE=" crossorigin="anonymous"></script>
        <script src="<?=base_url()?>application/asset/bootstrap/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
    </body>
</html>


text:
package com.google.errorprone.refaster;

import com.google.auto.value.AutoValue;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.errorprone.refaster.PlaceholderUnificationVisitor.State;
import com.google.errorprone.refaster.UPlaceholderExpression.PlaceholderParamIdent;
import com.google.errorprone.util.ASTHelpers;

import com.sun.source.tree.ArrayAccessTree;
import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.BlockTree;
import com.sun.source.tree.CaseTree;
import com.sun.source.tree.CatchTree;
import com.sun.source.tree.CompoundAssignmentTree;
import com.sun.source.tree.ConditionalExpressionTree;
import com.sun.source.tree.DoWhileLoopTree;
import com.sun.source.tree.EnhancedForLoopTree;
import com.sun.source.tree.ExpressionStatementTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.ForLoopTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.IfTree;
import com.sun.source.tree.InstanceOfTree;
import com.sun.source.tree.LabeledStatementTree;
import com.sun.source.tree.LambdaExpressionTree;
import com.sun.source.tree.MemberReferenceTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.NewArrayTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.ParenthesizedTree;
import com.sun.source.tree.ReturnTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.tree.SwitchTree;
import com.sun.source.tree.SynchronizedTree;
import com.sun.source.tree.ThrowTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.TreeVisitor;
import com.sun.source.tree.TryTree;
import com.sun.source.tree.TypeCastTree;
import com.sun.source.tree.UnaryTree;
import com.sun.source.tree.VariableTree;
import com.sun.source.tree.WhileLoopTree;
import com.sun.source.util.SimpleTreeVisitor;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCArrayAccess;
import com.sun.tools.javac.tree.JCTree.JCAssign;
import com.sun.tools.javac.tree.JCTree.JCAssignOp;
import com.sun.tools.javac.tree.JCTree.JCBinary;
import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCCase;
import com.sun.tools.javac.tree.JCTree.JCCatch;
import com.sun.tools.javac.tree.JCTree.JCConditional;
import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCForLoop;
import com.sun.tools.javac.tree.JCTree.JCIf;
import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
import com.sun.tools.javac.tree.JCTree.JCLabeledStatement;
import com.sun.tools.javac.tree.JCTree.JCLambda;
import com.sun.tools.javac.tree.JCTree.JCMemberReference;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
import com.sun.tools.javac.tree.JCTree.JCNewArray;
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCParens;
import com.sun.tools.javac.tree.JCTree.JCReturn;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCSwitch;
import com.sun.tools.javac.tree.JCTree.JCSynchronized;
import com.sun.tools.javac.tree.JCTree.JCThrow;
import com.sun.tools.javac.tree.JCTree.JCTry;
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
import com.sun.tools.javac.tree.JCTree.JCUnary;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
import com.sun.tools.javac.tree.JCTree.Tag;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;

import java.util.Collections;
import java.util.EnumSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nullable;

/**
 * Given a tree as input, returns all the ways this placeholder invocation could be matched with
 * that tree, represented as States, containing the {@code Unifier}, the list of all parameters of
 * the placeholder method that were unified with subtrees of the given tree, and a
 * {@code JCExpression} representing the implementation of the placeholder method, with references
 * to the placeholder parameters replaced with a corresponding {@code PlaceholderParamIdent}.
 */
@AutoValue
abstract class PlaceholderUnificationVisitor
    extends SimpleTreeVisitor<Choice<? extends State<? extends JCTree>>,
                              State<?>> {

  /**
   * Represents the state of a placeholder unification in progress, including the
   * current unifier state, the parameters of the placeholder method that have been bound,
   * and a result used to store additional state.
   */
  @AutoValue
  abstract static class State<R> {
    static <R> State<R> create(
        List<UVariableDecl> seenParameters, Unifier unifier, @Nullable R result) {
      return new AutoValue_PlaceholderUnificationVisitor_State<R>(
          seenParameters, unifier, result);
    }

    public abstract List<UVariableDecl> seenParameters();

    public abstract Unifier unifier();

    @Nullable
    public abstract R result();

    public <R2> State<R2> withResult(R2 result) {
      return create(seenParameters(), unifier(), result);
    }

    public State<R> fork() {
      return create(seenParameters(), unifier().fork(), result());
    }
  }

  public static PlaceholderUnificationVisitor create(
      TreeMaker maker,
      Map<UVariableDecl, UExpression> arguments) {
    return new AutoValue_PlaceholderUnificationVisitor(maker, ImmutableMap.copyOf(arguments));
  }

  abstract TreeMaker maker();
  abstract ImmutableMap<UVariableDecl, UExpression> arguments();

  /**
   * Returns all the ways this tree might be unified with the arguments to this placeholder
   * invocation. That is, if the placeholder invocation looks like
   * {@code placeholder(arg1, arg2, ...)}, then the {@code Choice} will contain any ways this
   * tree can be unified with {@code arg1}, {@code arg2}, or the other arguments.
   */
  Choice<State<PlaceholderParamIdent>> tryBindArguments(
      final ExpressionTree node, final State<?> state) {
    return Choice.from(arguments().entrySet())
        .thenChoose(new Function<Map.Entry<UVariableDecl, UExpression>,
                                 Choice<State<PlaceholderParamIdent>>>() {
          @Override
          public Choice<State<PlaceholderParamIdent>> apply(
              final Map.Entry<UVariableDecl, UExpression> entry) {
            return unifyParam(entry.getKey(), entry.getValue(), node, state.fork());
          }
        });
  }

  private Choice<State<PlaceholderParamIdent>> unifyParam(
      final UVariableDecl placeholderParam,
      UExpression placeholderArg,
      ExpressionTree toUnify,
      final State<?> state) {
    return placeholderArg.unify(toUnify, state.unifier()).transform(
        new Function<Unifier, State<PlaceholderParamIdent>>() {
          @Override
          public State<PlaceholderParamIdent> apply(Unifier unifier) {
            return State.create(state.seenParameters().prepend(placeholderParam), unifier,
                new PlaceholderParamIdent(placeholderParam, unifier.getContext()));
          }
        });
  }

  public Choice<? extends State<? extends JCTree>> unify(@Nullable Tree node, State<?> state) {
    if (node instanceof ExpressionTree) {
      return unifyExpression((ExpressionTree) node, state);
    } else if (node == null) {
      return Choice.of(state.<JCTree>withResult(null));
    } else {
      return node.accept(this, state);
    }
  }

  public Choice<State<List<JCTree>>> unify(
      @Nullable Iterable<? extends Tree> nodes, State<?> state) {
    if (nodes == null) {
      return Choice.of(state.<List<JCTree>>withResult(null));
    }
    Choice<State<List<JCTree>>> choice =
        Choice.of(state.withResult(List.<JCTree>nil()));
    for (final Tree node : nodes) {
      choice = choice.thenChoose(new Function<State<List<JCTree>>,
          Choice<State<List<JCTree>>>>() {
        @Override
        public Choice<State<List<JCTree>>> apply(
            final State<List<JCTree>> state) {
          return unify(node, state).transform(new Function<
              State<? extends JCTree>,
              State<List<JCTree>>>() {

            @Override
            public State<List<JCTree>> apply(
                State<? extends JCTree> treeState) {
              return treeState.withResult(state.result().prepend(treeState.result()));
            }
          });
        }
      });
    }
    return choice.transform(new Function<State<List<JCTree>>, State<List<JCTree>>>() {
      @Override
      public State<List<JCTree>> apply(State<List<JCTree>> state) {
        return state.withResult(state.result().reverse());
      }
    });
  }

  static boolean equivalentExprs(Unifier unifier, JCExpression expr1, JCExpression expr2) {
    return Types.instance(unifier.getContext()).isSameType(expr2.type, expr1.type)
        && expr2.toString().equals(expr1.toString());
  }

  /**
   * Verifies that the given tree does not directly conflict with an already-bound
   * {@code UFreeIdent} or {@code ULocalVarIdent}.
   */
  static final TreeVisitor<Boolean, Unifier> FORBIDDEN_REFERENCE_VISITOR =
      new SimpleTreeVisitor<Boolean, Unifier>() {
    @Override
    protected Boolean defaultAction(Tree node, Unifier unifier) {
      if (!(node instanceof JCExpression)) {
        return false;
      }
      JCExpression expr = (JCExpression) node;
      for (UFreeIdent.Key key :
           Iterables.filter(unifier.getBindings().keySet(), UFreeIdent.Key.class)) {
        JCExpression keyBinding = unifier.getBinding(key);
        if (equivalentExprs(unifier, expr, keyBinding)) {
          return true;
        }
      }
      return false;
    }

    @Override
    public Boolean visitIdentifier(IdentifierTree node, Unifier unifier) {
      for (LocalVarBinding localBinding :
           Iterables.filter(unifier.getBindings().values(), LocalVarBinding.class)) {
        if (localBinding.getSymbol().equals(ASTHelpers.getSymbol(node))) {
          return true;
        }
      }
      return defaultAction(node, unifier);
    }
  };

  /**
   * Returns all the ways this placeholder invocation might unify with the specified tree: either
   * by unifying the entire tree with an argument to the placeholder invocation, or by recursing
   * on the subtrees.
   */
  @SuppressWarnings("unchecked")
  public Choice<? extends State<? extends JCExpression>> unifyExpression(
      @Nullable ExpressionTree node, State<?> state) {
    if (node == null) {
      return Choice.of(state.<JCExpression>withResult(null));
    }
    Choice<? extends State<? extends JCExpression>> tryBindArguments =
        tryBindArguments(node, state);
    if (!node.accept(FORBIDDEN_REFERENCE_VISITOR, state.unifier())) {
      return tryBindArguments.or((Choice) node.accept(this, state));
    } else {
      return tryBindArguments;
    }
  }

  /**
   * Returns all the ways this placeholder invocation might unify with the specified list of
   * trees.
   */
  public Choice<State<List<JCExpression>>> unifyExpressions(
      @Nullable Iterable<? extends ExpressionTree> nodes, State<?> state) {
    return unify(nodes, state).transform(
        new Function<State<List<JCTree>>, State<List<JCExpression>>>() {
          @Override
          public State<List<JCExpression>> apply(State<List<JCTree>> state) {
            return state.withResult(List.convert(JCExpression.class, state.result()));
          }
        });
  }

  @SuppressWarnings("unchecked")
  public Choice<? extends State<? extends JCStatement>> unifyStatement(
      @Nullable StatementTree node, State<?> state) {
    return (Choice<? extends State<? extends JCStatement>>) unify(node, state);
  }

  public Choice<State<List<JCStatement>>> unifyStatements(
      @Nullable Iterable<? extends StatementTree> nodes, State<?> state) {
    return unify(nodes, state).transform(
        new Function<State<List<JCTree>>, State<List<JCStatement>>>() {
          @Override
          public State<List<JCStatement>> apply(State<List<JCTree>> state) {
            return state.withResult(List.convert(JCStatement.class, state.result()));
          }
        });
  }

  @Override
  protected Choice<State<JCTree>> defaultAction(
      Tree node, State<?> state) {
    return Choice.of(state.withResult((JCTree) node));
  }

  /*
   * All the visit methods look more or less like this one: we recursively visit the first
   * subnode of the provided tree, and for each unification state of that subnode, we
   * continue recursively through the next subnode, and when we have recursed through all
   * subnodes, we rebuild the same type of tree node with each subtree replaced by its copied or
   * replaced version.
   *
   * This looks much less ugly with lambdas and streams, but we can't use those yet.
   */

  @Override
  public Choice<State<JCArrayAccess>> visitArrayAccess(
      final ArrayAccessTree node, State<?> state) {
    return unifyExpression(node.getExpression(), state)
        .thenChoose(new Function<State<? extends JCExpression>,
                                 Choice<State<JCArrayAccess>>>() {
          @Override
          public Choice<State<JCArrayAccess>> apply(
              final State<? extends JCExpression> expressionState) {
            return unifyExpression(node.getIndex(), expressionState)
                .transform(new Function<State<? extends JCExpression>,
                                        State<JCArrayAccess>>() {
                  @Override
                  public State<JCArrayAccess> apply(
                      State<? extends JCExpression> indexState) {
                    return indexState.withResult(
                        maker().Indexed(expressionState.result(), indexState.result()));
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCBinary>> visitBinary(
      final BinaryTree node, State<?> state) {
    final Tag tag = ((JCBinary) node).getTag();
    return unifyExpression(node.getLeftOperand(), state)
        .thenChoose(new Function<State<? extends JCExpression>,
                                 Choice<State<JCBinary>>>() {
          @Override
          public Choice<State<JCBinary>> apply(
              final State<? extends JCExpression> leftState) {
            return unifyExpression(node.getRightOperand(), leftState)
                .transform(new Function<State<? extends JCExpression>,
                                        State<JCBinary>>() {
                  @Override
                  public State<JCBinary> apply(
                      State<? extends JCExpression> rightState) {
                    return rightState.withResult(
                        maker().Binary(tag, leftState.result(), rightState.result()));
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCMethodInvocation>> visitMethodInvocation(
      final MethodInvocationTree node, State<?> state) {
    return unifyExpression(node.getMethodSelect(), state)
        .thenChoose(new Function<State<? extends JCExpression>,
                                 Choice<State<JCMethodInvocation>>>() {
          @Override
          public Choice<State<JCMethodInvocation>> apply(
              final State<? extends JCExpression> selectState) {
            return unifyExpressions(node.getArguments(), selectState)
                .transform(new Function<State<List<JCExpression>>,
                                        State<JCMethodInvocation>>() {
                  @Override
                  public State<JCMethodInvocation> apply(
                      State<List<JCExpression>> argsState) {
                    return argsState.withResult(
                        maker().Apply(null, selectState.result(), argsState.result()));
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCFieldAccess>> visitMemberSelect(
      final MemberSelectTree node, State<?> state) {
    return unifyExpression(node.getExpression(), state)
        .transform(new Function<State<? extends JCExpression>,
                                State<JCFieldAccess>>() {
          @Override
          public State<JCFieldAccess> apply(
              State<? extends JCExpression> exprState) {
            return exprState.withResult(
                maker().Select(exprState.result(), (Name) node.getIdentifier()));
          }
        });
  }

  @Override
  public Choice<State<JCParens>> visitParenthesized(
      ParenthesizedTree node, State<?> state) {
    return unifyExpression(node.getExpression(), state)
        .transform(new Function<State<? extends JCExpression>,
                                State<JCParens>>() {
          @Override
          public State<JCParens> apply(
              State<? extends JCExpression> expressionState) {
            return expressionState.withResult(maker().Parens(expressionState.result()));
          }
        });
  }

  private static final Set<Tag> MUTATING_UNARY_TAGS =
      Collections.unmodifiableSet(EnumSet.of(Tag.PREINC, Tag.PREDEC, Tag.POSTINC, Tag.POSTDEC));

  @Override
  public Choice<State<JCUnary>> visitUnary(
      UnaryTree node, State<?> state) {
    final Tag tag = ((JCUnary) node).getTag();
    return unifyExpression(node.getExpression(), state)
        .thenOption(new Function<State<? extends JCExpression>,
                                Optional<State<JCUnary>>>() {
          @Override
          public Optional<State<JCUnary>> apply(
              State<? extends JCExpression> expressionState) {
            if (MUTATING_UNARY_TAGS.contains(tag)
                && expressionState.result() instanceof PlaceholderParamIdent) {
              return Optional.absent();
            }
            return Optional.of(
                expressionState.withResult(maker().Unary(tag, expressionState.result())));
          }
        });
  }

  @Override
  public Choice<State<JCTypeCast>> visitTypeCast(
      final TypeCastTree node, State<?> state) {
    return unifyExpression(node.getExpression(), state)
        .transform(new Function<State<? extends JCExpression>,
                                State<JCTypeCast>>() {
          @Override
          public State<JCTypeCast> apply(
              State<? extends JCExpression> expressionState) {
            return expressionState.withResult(
                maker().TypeCast((JCTree) node.getType(), expressionState.result()));
          }
        });
  }

  @Override
  public Choice<State<JCInstanceOf>> visitInstanceOf(
      final InstanceOfTree node, State<?> state) {
    return unifyExpression(node.getExpression(), state)
        .transform(new Function<State<? extends JCExpression>,
                                State<JCInstanceOf>>() {
          @Override
          public State<JCInstanceOf> apply(
              State<? extends JCExpression> expressionState) {
            return expressionState.withResult(
                maker().TypeTest(expressionState.result(), (JCTree) node.getType()));
          }
        });
  }

  @Override
  public Choice<State<JCNewClass>> visitNewClass(
      final NewClassTree node, State<?> state) {
    if (node.getEnclosingExpression() != null
        || (node.getTypeArguments() != null && !node.getTypeArguments().isEmpty())
        || node.getClassBody() != null) {
      return Choice.none();
    }
    return unifyExpression(node.getIdentifier(), state)
        .thenChoose(new Function<State<? extends JCExpression>,
                                 Choice<State<JCNewClass>>>() {
          @Override
          public Choice<State<JCNewClass>> apply(
              final State<? extends JCExpression> identifierState) {
            return unifyExpressions(node.getArguments(), identifierState)
                .transform(new Function<State<List<JCExpression>>,
                                        State<JCNewClass>>() {
                  @Override
                  public State<JCNewClass> apply(
                      State<List<JCExpression>> argsState) {
                    return argsState.withResult(maker().NewClass(
                        null, null, identifierState.result(), argsState.result(), null));
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCNewArray>> visitNewArray(
      final NewArrayTree node, State<?> state) {
    return unifyExpressions(node.getDimensions(), state)
        .thenChoose(new Function<State<List<JCExpression>>,
                                 Choice<State<JCNewArray>>>() {
          @Override
          public Choice<State<JCNewArray>> apply(
              final State<List<JCExpression>> dimsState) {
            return unifyExpressions(node.getInitializers(), dimsState)
                .transform(new Function<State<List<JCExpression>>,
                                        State<JCNewArray>>() {
                  @Override
                  public State<JCNewArray> apply(
                      State<List<JCExpression>> initsState) {
                    return initsState.withResult(maker().NewArray(
                        (JCExpression) node.getType(), dimsState.result(), initsState.result()));
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCConditional>> visitConditionalExpression(
      final ConditionalExpressionTree node, State<?> state) {
    return unifyExpression(node.getCondition(), state)
        .thenChoose(new Function<State<? extends JCExpression>,
                                 Choice<State<JCConditional>>>() {

          @Override
          public Choice<State<JCConditional>> apply(
              final State<? extends JCExpression> condState) {
            return unifyExpression(node.getTrueExpression(), condState)
                .thenChoose(new Function<State<? extends JCExpression>,
                                         Choice<State<JCConditional>>>() {
                  @Override
                  public Choice<State<JCConditional>> apply(
                      final State<? extends JCExpression> trueState) {
                    return unifyExpression(node.getFalseExpression(), trueState)
                        .transform(
                            new Function<State<? extends JCExpression>,
                                         State<JCConditional>>() {
                              @Override
                              public State<JCConditional> apply(
                                  State<? extends JCExpression>
                                  falseState) {
                                return falseState.withResult(maker().Conditional(
                                    condState.result(), trueState.result(), falseState.result()));
                              }
                            });
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCAssign>> visitAssignment(
      final AssignmentTree node, State<?> state) {
    return unifyExpression(node.getVariable(), state)
        .thenChoose(new Function<State<? extends JCExpression>,
                                 Choice<State<JCAssign>>>() {

          @Override
          public Choice<State<JCAssign>> apply(
              final State<? extends JCExpression> varState) {
            if (varState.result() instanceof PlaceholderParamIdent) {
              // forbid assignment to placeholder variables
              return Choice.none();
            }
            return unifyExpression(node.getExpression(), varState)
                .transform(new Function<State<? extends JCExpression>,
                                        State<JCAssign>>() {
                  @Override
                  public State<JCAssign> apply(
                      State<? extends JCExpression> exprState) {
                    return exprState.withResult(
                        maker().Assign(varState.result(), exprState.result()));
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCAssignOp>> visitCompoundAssignment(
      final CompoundAssignmentTree node, State<?> state) {
    return unifyExpression(node.getVariable(), state).thenChoose(
        new Function<State<? extends JCExpression>, Choice<State<JCAssignOp>>>() {
          @Override
          public Choice<State<JCAssignOp>> apply(final State<? extends JCExpression> varState) {
            if (varState.result() instanceof PlaceholderParamIdent) {
              // forbid assignment to placeholder variables
              return Choice.none();
            }
            return unifyExpression(node.getExpression(), varState).transform(
                new Function<State<? extends JCExpression>, State<JCAssignOp>>() {
                  @Override
                  public State<JCAssignOp> apply(State<? extends JCExpression> exprState) {
                    return exprState.withResult(maker().Assignop(((JCAssignOp) node).getTag(),
                        varState.result(), exprState.result()));
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCExpressionStatement>> visitExpressionStatement(
      ExpressionStatementTree node, State<?> state) {
    return unifyExpression(node.getExpression(), state).transform(new Function<
        State<? extends JCExpression>,
        State<JCExpressionStatement>>() {
      @Override
      public State<JCExpressionStatement> apply(
          State<? extends JCExpression> exprState) {
        return exprState.withResult(maker().Exec(exprState.result()));
      }
    });
  }

  @Override
  public Choice<State<JCBlock>> visitBlock(BlockTree node,
      State<?> state) {
    return unifyStatements(node.getStatements(), state).transform(new Function<
        State<List<JCStatement>>, State<JCBlock>>() {

      @Override
      public State<JCBlock> apply(
          State<List<JCStatement>> state) {
        return state.withResult(maker().Block(0, state.result()));
      }
    });
  }

  @Override
  public Choice<State<JCThrow>> visitThrow(ThrowTree node,
      State<?> state) {
    return unifyExpression(node.getExpression(), state).transform(new Function<
        State<? extends JCExpression>,
        State<JCThrow>>() {

      @Override
      public State<JCThrow> apply(
          State<? extends JCExpression> exprState) {
        return exprState.withResult(maker().Throw(exprState.result()));
      }
    });
  }

  @Override
  public Choice<State<JCEnhancedForLoop>> visitEnhancedForLoop(
      final EnhancedForLoopTree node, State<?> state) {
    return unifyExpression(node.getExpression(), state).thenChoose(new Function<
        State<? extends JCExpression>,
        Choice<State<JCEnhancedForLoop>>>() {

      @Override
      public Choice<State<JCEnhancedForLoop>> apply(
          final State<? extends JCExpression> exprState) {
        return unifyStatement(node.getStatement(), exprState).transform(new Function<
            State<? extends JCStatement>,
            State<JCEnhancedForLoop>>() {

          @Override
          public State<JCEnhancedForLoop> apply(
              State<? extends JCStatement> stmtState) {
            return stmtState.withResult(
                maker().ForeachLoop(
                    (JCVariableDecl) node.getVariable(),
                    exprState.result(),
                    stmtState.result()));
          }
        });
      }
    });
  }

  @Override
  public Choice<State<JCIf>> visitIf(final IfTree node, State<?> state) {
    return unifyExpression(node.getCondition(), state).thenChoose(
        new Function<State<? extends JCExpression>, Choice<State<JCIf>>>() {
          @Override
          public Choice<State<JCIf>> apply(final State<? extends JCExpression> condState) {
            return unifyStatement(node.getThenStatement(), condState).thenChoose(
                new Function<State<? extends JCStatement>, Choice<State<JCIf>>>() {
                  @Override
                  public Choice<State<JCIf>> apply(final State<? extends JCStatement> thenState) {
                    return unifyStatement(node.getElseStatement(), thenState).transform(
                        new Function<State<? extends JCStatement>, State<JCIf>>() {
                          @Override
                          public State<JCIf> apply(State<? extends JCStatement> elseState) {
                            return elseState.withResult(maker().If(condState.result(),
                                thenState.result(), elseState.result()));
                          }
                        });
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCDoWhileLoop>> visitDoWhileLoop(final DoWhileLoopTree node,
      State<?> state) {
    return unifyStatement(node.getStatement(), state).thenChoose(
        new Function<State<? extends JCStatement>, Choice<State<JCDoWhileLoop>>>() {

          @Override
          public Choice<State<JCDoWhileLoop>> apply(
              final State<? extends JCStatement> stmtState) {
            return unifyExpression(node.getCondition(), stmtState).transform(
                new Function<State<? extends JCExpression>, State<JCDoWhileLoop>>() {

                  @Override
                  public State<JCDoWhileLoop> apply(State<? extends JCExpression> condState) {
                    return condState.withResult(
                        maker().DoLoop(stmtState.result(), condState.result()));
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCForLoop>> visitForLoop(final ForLoopTree node, State<?> state) {
    return unifyStatements(node.getInitializer(), state).thenChoose(
        new Function<State<List<JCStatement>>, Choice<State<JCForLoop>>>() {

          @Override
          public Choice<State<JCForLoop>> apply(final State<List<JCStatement>> initsState) {
            return unifyExpression(node.getCondition(), initsState).thenChoose(
                new Function<State<? extends JCExpression>, Choice<State<JCForLoop>>>() {

                  @Override
                  public Choice<State<JCForLoop>> apply(
                      final State<? extends JCExpression> condState) {
                    return unifyStatements(node.getUpdate(), condState).thenChoose(
                        new Function<State<List<JCStatement>>, Choice<State<JCForLoop>>>() {

                          @Override
                          public Choice<State<JCForLoop>> apply(
                              final State<List<JCStatement>> updateState) {
                            return unifyStatement(node.getStatement(), updateState).transform(
                                new Function<State<? extends JCStatement>, State<JCForLoop>>() {

                                  @Override
                                  public State<JCForLoop> apply(
                                      State<? extends JCStatement> stmtState) {
                                    return stmtState.withResult(maker().ForLoop(initsState.result(),
                                        condState.result(), List.convert(
                                            JCExpressionStatement.class, updateState.result()),
                                        stmtState.result()));
                                  }
                                });
                          }
                        });
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCLabeledStatement>> visitLabeledStatement(
      final LabeledStatementTree node, State<?> state) {
    return unifyStatement(node.getStatement(), state).transform(
        new Function<State<? extends JCStatement>, State<JCLabeledStatement>>() {
          @Override
          public State<JCLabeledStatement> apply(State<? extends JCStatement> stmtState) {
            return stmtState.withResult(
                maker().Labelled((Name) node.getLabel(), stmtState.result()));
          }
        });
  }

  @Override
  public Choice<State<JCVariableDecl>> visitVariable(final VariableTree node, State<?> state) {
    return unifyExpression(node.getInitializer(), state).transform(
        new Function<State<? extends JCExpression>, State<JCVariableDecl>>() {

          @Override
          public State<JCVariableDecl> apply(State<? extends JCExpression> initState) {
            return initState.withResult(maker().VarDef((JCModifiers) node.getModifiers(),
                (Name) node.getName(), (JCExpression) node.getType(), initState.result()));
          }
        });
  }

  @Override
  public Choice<State<JCWhileLoop>> visitWhileLoop(final WhileLoopTree node, State<?> state) {
    return unifyExpression(node.getCondition(), state).thenChoose(
        new Function<State<? extends JCExpression>, Choice<State<JCWhileLoop>>>() {
          @Override
          public Choice<State<JCWhileLoop>> apply(final State<? extends JCExpression> condState) {
            return unifyStatement(node.getStatement(), condState).transform(
                new Function<State<? extends JCStatement>, State<JCWhileLoop>>() {
                  @Override
                  public State<JCWhileLoop> apply(State<? extends JCStatement> stmtState) {
                    return stmtState.withResult(
                        maker().WhileLoop(condState.result(), stmtState.result()));
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCSynchronized>> visitSynchronized(final SynchronizedTree node,
      State<?> state) {
    return unifyExpression(node.getExpression(), state).thenChoose(
        new Function<State<? extends JCExpression>, Choice<State<JCSynchronized>>>() {

          @Override
          public Choice<State<JCSynchronized>> apply(
              final State<? extends JCExpression> exprState) {
            return unifyStatement(node.getBlock(), exprState).transform(
                new Function<State<? extends JCStatement>, State<JCSynchronized>>() {

                  @Override
                  public State<JCSynchronized> apply(State<? extends JCStatement> blockState) {
                    return blockState.withResult(
                        maker().Synchronized(exprState.result(), (JCBlock) blockState.result()));
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCReturn>> visitReturn(ReturnTree node, State<?> state) {
    return unifyExpression(node.getExpression(), state).transform(
        new Function<State<? extends JCExpression>, State<JCReturn>>() {
          @Override
          public State<JCReturn> apply(State<? extends JCExpression> exprState) {
            return exprState.withResult(maker().Return(exprState.result()));
          }
        });
  }

  @Override
  public Choice<State<JCTry>> visitTry(final TryTree node, State<?> state) {
    return unify(node.getResources(), state).thenChoose(
        new Function<State<List<JCTree>>, Choice<State<JCTry>>>() {
          @Override
          public Choice<State<JCTry>> apply(final State<List<JCTree>> resourcesState) {
            return unifyStatement(node.getBlock(), resourcesState).thenChoose(
                new Function<State<? extends JCStatement>, Choice<State<JCTry>>>() {
                  @Override
                  public Choice<State<JCTry>> apply(
                      final State<? extends JCStatement> blockState) {
                    return unify(node.getCatches(), blockState).thenChoose(
                        new Function<State<List<JCTree>>, Choice<State<JCTry>>>() {
                          @Override
                          public Choice<State<JCTry>> apply(
                              final State<List<JCTree>> catchesState) {
                            return unifyStatement(node.getFinallyBlock(), catchesState).transform(
                                new Function<State<? extends JCStatement>, State<JCTry>>() {
                                  @Override
                                  public State<JCTry> apply(
                                      State<? extends JCStatement> finallyState) {
                                    return finallyState.withResult(maker().Try(
                                        resourcesState.result(), (JCBlock) blockState.result(),
                                        List.convert(JCCatch.class, catchesState.result()),
                                        (JCBlock) finallyState.result()));
                                  }
                                });
                          }
                        });
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCCatch>> visitCatch(final CatchTree node, State<?> state) {
    return unifyStatement(node.getBlock(), state).transform(
        new Function<State<? extends JCStatement>, State<JCCatch>>() {
          @Override
          public State<JCCatch> apply(State<? extends JCStatement> blockState) {
            return blockState.withResult(maker().Catch(
                (JCVariableDecl) node.getParameter(),
                (JCBlock) blockState.result()));
          }
        });
  }

  @Override
  public Choice<State<JCSwitch>> visitSwitch(final SwitchTree node, State<?> state) {
    return unifyExpression(node.getExpression(), state).thenChoose(
        new Function<State<? extends JCExpression>, Choice<State<JCSwitch>>>() {
          @Override
          public Choice<State<JCSwitch>> apply(final State<? extends JCExpression> exprState) {
            return unify(node.getCases(), exprState).transform(
                new Function<State<List<JCTree>>, State<JCSwitch>>() {
                  @Override
                  public State<JCSwitch> apply(State<List<JCTree>> casesState) {
                    return casesState.withResult(maker().Switch(exprState.result(),
                        List.convert(JCCase.class, casesState.result())));
                  }
                });
          }
        });
  }

  @Override
  public Choice<State<JCCase>> visitCase(final CaseTree node, State<?> state) {
    return unifyStatements(node.getStatements(), state).transform(
        new Function<State<List<JCStatement>>, State<JCCase>>() {
          @Override
          public State<JCCase> apply(State<List<JCStatement>> stmtsState) {
            return stmtsState.withResult(
                maker().Case((JCExpression) node.getExpression(), stmtsState.result()));
          }
        });
  }

  @Override
  public Choice<State<JCLambda>> visitLambdaExpression(
      final LambdaExpressionTree node, State<?> state) {
    return unify(node.getBody(), state).transform(
        new Function<State<? extends JCTree>, State<JCLambda>>() {
          @Override
          public State<JCLambda> apply(State<? extends JCTree> bodyState) {
            return bodyState.withResult(maker().Lambda(
                List.convert(JCVariableDecl.class,
                    (List<? extends VariableTree>) node.getParameters()),
                bodyState.result()));
          }
        });
  }

  @Override
  public Choice<State<JCMemberReference>> visitMemberReference(final MemberReferenceTree node,
      State<?> state) {
    return unifyExpression(node.getQualifierExpression(), state).transform(
        new Function<State<? extends JCExpression>, State<JCMemberReference>>() {
          @Override
          public State<JCMemberReference> apply(State<? extends JCExpression> exprState) {
            return exprState.withResult(maker().Reference(node.getMode(), (Name) node.getName(),
                exprState.result(),
                List.convert(JCExpression.class,
                    (List<? extends ExpressionTree>) node.getTypeArguments())));
          }
        });
  }
}


text:
import platform

if platform.python_version() < '2.7':
    import unittest2 as unittest
else:
    import unittest

# TODO test with a fake Mongo DB and with a real one, created for these tests
import pymongo
from remindme import store

class TestStore(unittest.TestCase):

    def setUp(self):
        self.fake_db = {}
        self._get_db = store.get_db
        self._mongoclient = pymongo.MongoClient

        def fake_get_db():
            return self.fake_db

        def fake_client(*args, **kw):
            return {'remindme': self.fake_db}

        store.get_db = fake_get_db
        pymongo.MongoClient = fake_client

    def tearDown(self):
        store.get_db = self._get_db
        pymongo.MongoClient = self._mongoclient

    def test_connect_db_return_db_obj(self):
        k, v = 'foox1a2z', 'xsa3%d'

        self.fake_db[k] = v
        store.connect_db()
        self.assertIn(k, store.db)
        self.assertEquals(store.db[k], v)


text:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using Rikrop.Core.Framework.Services;

namespace Rikrop.Core.Wpf.Collections
{
    public class ServiceExecutorItemLoaderBuilder1<TService, TItem>
    {
        private readonly IServiceExecutor<TService> _serviceExecutor;
        private readonly ObservableCollection<TItem> _targetCollection;
        private readonly bool _isAutoLoading;

        internal ServiceExecutorItemLoaderBuilder1(IServiceExecutor<TService> serviceExecutor, ObservableCollection<TItem> targetCollection, bool isAutoLoading)
        {
            _serviceExecutor = serviceExecutor;
            _targetCollection = targetCollection;
            _isAutoLoading = isAutoLoading;
        }

        public ServiceExecutorItemLoaderBuilder2<TService, TItem> LoadWith(Func<TService, Task<IReadOnlyList<TItem>>> itemsLoaderFunc)
        {
            return new ServiceExecutorItemLoaderBuilder2<TService, TItem>(_serviceExecutor, _targetCollection, _isAutoLoading, itemsLoaderFunc);
        }
    }

    public class ServiceExecutorItemLoaderBuilder1<TService, TServiceItem, TItem>
    {
        private readonly IServiceExecutor<TService> _serviceExecutor;
        private readonly ObservableCollection<TItem> _targetCollection;
        private readonly bool _isAutoLoading;

        internal ServiceExecutorItemLoaderBuilder1(IServiceExecutor<TService> serviceExecutor, ObservableCollection<TItem> targetCollection, bool isAutoLoading)
        {
            _serviceExecutor = serviceExecutor;
            _targetCollection = targetCollection;
            _isAutoLoading = isAutoLoading;
        }

        public ServiceExecutorItemLoaderBuilder2<TService, TServiceItem, TItem> LoadWith(Func<TService, Task<IReadOnlyList<TServiceItem>>> itemsLoaderFunc)
        {
            return new ServiceExecutorItemLoaderBuilder2<TService, TServiceItem, TItem>(_serviceExecutor, _targetCollection, _isAutoLoading, itemsLoaderFunc);
        }
    }
}