text:
import hasUsableConsole from 'hasUsableConsole';
import { isArray } from 'utils/is';
import cleanup from 'helpers/cleanup';

Array.isArray || ( Array.isArray = thing => isArray( thing ) ); // IE8... don't ask

var Foo, fooAdaptor;

Foo = function ( content ) {
	this.content = content;
};

fooAdaptor = {
	filter: function ( object ) {
		return object instanceof Foo;
	},
	wrap: function ( ractive, foo, keypath, prefix ) {
		return {
			get: function () {
				return foo.content;
			},
			teardown: function () {

			}
		};
	}
};

module( 'Miscellaneous', {
	beforeEach () {
		Ractive.adaptors.foo = fooAdaptor;
	},
	afterEach () {
		delete Ractive.adaptors.foo;
		cleanup();
	}
} );

test( 'Subclass instance data extends prototype data', function ( t ) {
	var Subclass, instance;

	Subclass = Ractive.extend({
		template: '{{foo}} {{bar}}',
		data: { foo: 1 }
	});

	instance = new Subclass({
		el: fixture,
		data: { bar: 2 }
	});

	t.htmlEqual( fixture.innerHTML, '1 2' );
	t.deepEqual( instance.get(), { foo: 1, bar: 2 });
});

test( 'Subclasses of subclasses inherit data, partials and transitions', function ( t ) {
	var Subclass, SubSubclass, wiggled, shimmied, instance;

	Subclass = Ractive.extend({
		template: '
{{>foo}}{{>bar}}{{>baz}}

{{foo}}{{bar}}{{baz}}
',
		data: { foo: 1 },
		partials: { foo: 'fooPartial' },
		transitions: { wiggle: function ( t ) { wiggled = true; } }
	});

	SubSubclass = Subclass.extend({
		data: { bar: 2 },
		partials: { bar: 'barPartial' },
		transitions: { shimmy: function ( t ) { shimmied = true; } }
	});

	instance = new SubSubclass({
		el: fixture,
		data: { baz: 3 },
		partials: { baz: 'bazPartial' }
	});

	t.htmlEqual( fixture.innerHTML, '
fooPartialbarPartialbazPartial

123
' );
	t.ok( wiggled );
	t.ok( shimmied );
});

// Commenting out - can't think of a way to test this in 0.8
// test( 'Multiple identical evaluators merge', function ( t ) {
// 	var ractive;
//
// 	ractive = new Ractive({
// 		el: fixture,
// 		template: '{{( a+b )}} {{( a+b )}} {{( a+b )}}',
// 		data: { a: 1, b: 2 }
// 	});
//
// 	t.htmlEqual( fixture.innerHTML, '3 3 3' );
//
// 	t.equal( ractive.viewmodel.root.propertyHash.a.dependants.methods.mark.length, 1 );
// 	t.equal( ractive.viewmodel.root.propertyHash.b.dependants.methods.mark.length, 1 );
// 	t.equal( ractive.viewmodel.root.properties.length, 3 );
// });

test( 'Boolean attributes work as expected', function ( t ) {
	var ractive;

	ractive = new Ractive({
		el: fixture,
		template: '<input id="one" type="checkbox" checked="{{falsy}}"><input id="two" type="checkbox" checked="{{truthy}}">',
		data: { truthy: true, falsy: false }
	});

	t.equal( ractive.nodes.one.checked, false );
	t.equal( ractive.nodes.two.checked, true );
});

test( 'Instances can be created without an element', function ( t ) {
	var ractive;

	ractive = new Ractive({
		template: '
{{#items:i}}
{{i}}: {{.}}
{{/items}}
',
		data: { items: [ 'a', 'b', 'c' ] }
	});

	t.ok( ractive );
});

test( 'Instances without an element can render HTML', function ( t ) {
	var ractive;

	ractive = new Ractive({
		template: '
{{#items:i}}
{{i}}: {{.}}
{{/items}}
',
		data: { items: [ 'a', 'b', 'c' ] }
	});

	t.htmlEqual( ractive.toHTML(), '

0: a

1: b

2: c

' );
});

test( 'Triples work with toHTML', function ( t ) {
	var ractive;

	ractive = new Ractive({
		template: '{{{ triple }}}',
		data: { triple: '
test
' }
	});

	t.htmlEqual( ractive.toHTML(), '
test
' );
});

test( 'Passing in alternative delimiters', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '/~ greeting ~/, /~recipient~/! /~~ triple ~~/',
		data: {
			greeting: 'Hello',
			recipient: 'world',
			triple: '
here is some HTML
'
		},
		delimiters: [ '/~', '~/' ],
		tripleDelimiters: [ '/~~', '~~/' ]
	});

	t.htmlEqual( fixture.innerHTML, 'Hello, world!
here is some HTML
' );
});

test( 'Using alternative delimiters in template', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '{{=/~ ~/=}} {{{=/~~ ~~/=}}} /~ greeting ~/, /~recipient~/! /~~ triple ~~/',
		data: {
			greeting: 'Hello',
			recipient: 'world',
			triple: '
here is some HTML
'
		}
	});

	t.htmlEqual( fixture.innerHTML, 'Hello, world!
here is some HTML
' );
});

test( '.unshift() works with proxy event handlers, without index references', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '{{#items}}<button on-click="bla">Level1: {{ title }}</button>{{/items}}',
		data: {
			items: [{ title: 'Title1' }]
		}
	});

	ractive.unshift( 'items', { title: 'Title0' } );

	t.htmlEqual( fixture.innerHTML, '<button>Level1: Title0</button><button>Level1: Title1</button>' );
});

test( 'Updating values with properties corresponding to unresolved references works', function ( t ) {
	var ractive, user;

	user = {};

	ractive = new Ractive({
		el: fixture,
		template: '{{#user}}{{name}}{{/user}}',
		data: { user: user }
	});

	t.equal( fixture.innerHTML, '' );
	user.name = 'Jim';
	ractive.update( 'user' );
	t.equal( fixture.innerHTML, 'Jim' );
});

test( 'Setting nested properties with a keypath correctly updates value of intermediate keypaths', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '{{#foo}}{{#bar}}{{baz}}{{/bar}}{{/foo}}'
	});

	ractive.set( 'foo.bar.baz', 'success' );

	t.htmlEqual( fixture.innerHTML, 'success' );
});

test( 'Functions are called with the ractive instance as context', function ( t ) {
	expect( 1 );

	var ractive = new Ractive({
		el: fixture,
		template: '{{ foo() }}'
	});

	ractive.set( 'foo', function () {
		t.equal( this, ractive );
	});
});

test( 'Methods are called with their object as context', function ( t ) {
	expect( 1 );

	var foo, run, ractive = new Ractive({
		el: fixture,
		template: '{{ foo.bar() }}'
	});

	foo = {
		bar: function () {
			// TODO why is this running twice?
			if ( !run ) {
				t.equal( this, foo );
			}

			run = true;
		}
	};

	ractive.set( 'foo', foo );
});

test( 'Delimiters can be reset globally', function ( t ) {
	var oldDelimiters, oldTripledDelimiters, ractive;

	oldDelimiters = Ractive.defaults.delimiters;
	oldTripledDelimiters = Ractive.defaults.tripleDelimiters;

	Ractive.defaults.delimiters = [ '/~', '~/' ];
	Ractive.defaults.tripleDelimiters = [ '/~~', '~~/' ];

	ractive = new Ractive({
		el: fixture,
		template: '/~foo~/ /~~bar~~/',
		data: { foo: 'text', bar: 'html' }
	});

	t.htmlEqual( fixture.innerHTML, 'text html' );

	Ractive.defaults.delimiters = oldDelimiters;
	Ractive.defaults.tripleDelimiters = oldTripledDelimiters;
});

test( 'Teardown works without throwing an error (#205)', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: 'a {{generic}} template',
		data: { generic: 'bog standard' }
	});

	expect( 1 );

	try {
		ractive.teardown();
		t.ok( 1 );
	} catch ( err ) {
		t.ok( 0 );
	}
});

test( 'Bindings without explicit keypaths can survive a splice operation', function ( t ) {
	var items, ractive;

	items = new Array( 3 );

	ractive = new Ractive({
		el: fixture,
		template: '
{{#items}}
<input value="{{foo}}">
{{/items}}
',
		data: { items: items }
	});

	expect( 1 );

	ractive.splice( 'items', 1, 1 );
	try {
		ractive.splice( 'items', 1, 1 );
		t.ok( 1 );
	} catch ( err ) {
		t.ok( 0 );
	}
});

test( 'Keypath resolutions that trigger teardowns don\'t cause the universe to implode', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '{{^foo}}not foo{{/foo}}{{#foo}}<widget items="{{items}}"/>{{/foo}}',
		data: { items: [ 1, 2 ] },
		components: {
			widget: Ractive.extend({ template: 'widget' })
		}
	});

	expect( 1 );

	try {
		ractive.set( 'foo', true );
		t.ok( 1 );
	} catch ( err ) {
		t.ok( 0 );
	}
});

test( 'Inverted sections aren\'t broken by unshift operations', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '{{^items}}no items{{/items}}{{#items}}{{.}}{{/items}}',
		data: { items: [] }
	});

	t.htmlEqual( fixture.innerHTML, 'no items' );
	ractive.unshift( 'items', 'foo' );
	t.htmlEqual( fixture.innerHTML, 'foo' );
});

test( 'Splice operations that try to remove more items than there are from an array are handled', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '{{#items}}{{.}}{{/items}}',
		data: { items: [ 'a', 'b', 'c' ] }
	});

	t.htmlEqual( fixture.innerHTML, 'abc' );
	ractive.splice( 'items', 2, 2 );
	t.htmlEqual( fixture.innerHTML, 'ab' );
});

test( 'Partial templates will be drawn from script tags if not already registered', function ( t ) {
	var partialScr, ractive;

	partialScr = document.createElement( 'script' );
	partialScr.id = 'thePartial';
	partialScr.type = 'text/ractive';
	partialScr.textContent = '{{one}}{{two}}{{three}}';

	document.getElementsByTagName('body')[0].appendChild( partialScr );

	ractive = new Ractive({
		el: fixture,
		template: '{{>thePartial}}',
		data: { one: 1, two: 2, three: 3 }
	});

	t.htmlEqual( fixture.innerHTML, '123' );
});

// ARGH these tests don't work in phantomJS
/*test( 'ractive.detach() removes an instance from the DOM and returns a document fragment', function ( t ) {
	var ractive, p, docFrag;

	ractive = new Ractive({
		el: fixture,
		template: '
{{foo}}
',
		data: { foo: 'whee!' }
	});

	p = ractive.find( 'p' );

	docFrag = ractive.detach();
	t.ok( docFrag instanceof DocumentFragment );
	t.ok( docFrag.contains( p ) );
});

test( 'ractive.detach() works with a previously unrendered ractive', function ( t ) {
	var ractive, p, docFrag;

	ractive = new Ractive({
		template: '
{{foo}}
',
		data: { foo: 'whee!' }
	});

	p = ractive.find( 'p' );

	docFrag = ractive.detach();
	t.ok( docFrag instanceof DocumentFragment );
	t.ok( docFrag.contains( p ) );
});*/

test( 'ractive.insert() moves an instance to a different location', function ( t ) {
	var ractive, p, one, two, three;

	one = document.createElement( 'div' );
	two = document.createElement( 'div' );

	three = document.createElement( 'div' );
	three.innerHTML = '
before

after
';

	ractive = new Ractive({
		el: fixture,
		template: '
{{foo}}
',
		data: { foo: 'whee!' }
	});

	p = ractive.find( 'p' );

	ractive.insert( one );
	t.ok( one.contains( p ) );

	ractive.insert( two );
	t.ok( !one.contains( p ) );
	t.ok( two.contains( p ) );

	ractive.insert( three, three.querySelector( '.after' ) );
	t.ok( three.contains( p ) );
	t.htmlEqual( three.innerHTML, '
before

whee!

after
' );
});

test( 'ractive.insert() throws an error if instance is not rendered (#712)', function ( t ) {
	var ractive, p, one, two, three;

	one = document.createElement( 'div' );
	two = document.createElement( 'div' );

	three = document.createElement( 'div' );
	three.innerHTML = '
before

after
';

	ractive = new Ractive({
		template: '
{{foo}}
',
		data: { foo: 'whee!' }
	});

	try {
		ractive.insert( one );
		t.ok( false );
	} catch ( err ) {
		t.ok( true );
	}

	ractive.render( two );
	p = ractive.find( 'p' );
	t.ok( !one.contains( p ) );
	t.ok( two.contains( p ) );

	ractive.insert( three, three.querySelector( '.after' ) );
	t.ok( three.contains( p ) );
	t.htmlEqual( three.innerHTML, '
before

whee!

after
' );
});

test( 'Regression test for #271', function ( t ) {
	var ractive, items;

	items = [{}];
	ractive = new Ractive({
		el: fixture,
		template: '{{#items}}
foo
{{# items.length > 1 }}
bar
{{/}}{{/items}}',
		data: { items: items }
	});

	t.htmlEqual( fixture.innerHTML, '
foo
' );

	ractive.push( 'items', {});
	t.htmlEqual( fixture.innerHTML, '
foo

bar

foo

bar
' );
	ractive.push( 'items', {});
	t.htmlEqual( fixture.innerHTML, '
foo

bar

foo

bar

foo

bar
' );

	ractive.splice( 'items', 1, 1 );
	t.htmlEqual( fixture.innerHTML, '
foo

bar

foo

bar
' );
	ractive.splice( 'items', 1, 1 );
	t.htmlEqual( fixture.innerHTML, '
foo
' );
});

test( 'Partials in shuffled sections are updated/removed correctly (#297)', function ( t ) {
	var ractive, items;

	items = [ 'one', 'two', 'three' ];

	ractive = new Ractive({
		el: fixture,
		template: '{{#items}}{{>item}}{{/items}}',
		data: { items: items },
		partials: {
			item: '
{{.}}
'
		}
	});

	t.htmlEqual( fixture.innerHTML, '
one

two

three
' );

	ractive.splice( 'items', 1, 1 );
	t.htmlEqual( fixture.innerHTML, '
one

three
' );
});

test( 'Regression test for #316', function ( t ) {
	var ractive, a, b;

	a = [];
	b = [];

	ractive = new Ractive({
		el: fixture,
		template: '{{ a.length ? "foo" : b.length ? "bar" : "baz" }}',
		data: { a: a, b: b }
	});

	t.htmlEqual( fixture.innerHTML, 'baz' );

	ractive.push( 'b', 1 );
	t.htmlEqual( fixture.innerHTML, 'bar' );

	ractive.push( 'a', 1 );
	t.htmlEqual( fixture.innerHTML, 'foo' );
});

test( 'Regression test for #321', function ( t ) {
	var ractive, buttons, expected;

	ractive = new Ractive({
		el: fixture,
		template: '<button on-click=\'test:{{ ["just a string"] }}\'>test 1</button><button on-click=\'test:{{ {bar: 3} }}\'>test 2</button>'
	});

	ractive.on( 'test', function ( event, arg ) {
		t.deepEqual( arg, expected );
	});

	expect( 2 );
	buttons = ractive.findAll( 'button' );

	expected = ['just a string'];
	simulant.fire( buttons[0], 'click' );

	expected = { bar: 3 };
	simulant.fire( buttons[1], 'click' );
});

test( 'Evaluators that have a value of undefined behave correctly', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '{{ list[index] }}',
		data: {
			index: 0,
			list: [ 'foo' ]
		}
	});

	t.htmlEqual( fixture.innerHTML, 'foo' );

	ractive.set( 'index', 1 );
	t.htmlEqual( fixture.innerHTML, '' );
});

test( 'Components inherit adaptors from their parent', function ( t ) {
	var ractive;

	Ractive.components.widget = Ractive.extend({
		template: '
{{wrappedThing}}
'
	});

	ractive = new Ractive({
		el: fixture,
		template: '<widget wrappedThing="{{thing}}"/>',
		adapt: [ 'foo' ],
		data: {
			thing: new Foo( 'whee!' )
		}
	});

	t.htmlEqual( fixture.innerHTML, '
whee!
' );
});

test( 'Components made with Ractive.extend() can include adaptors', function ( t ) {
	var Widget, ractive;

	Widget = Ractive.extend({
		adapt: [ 'foo' ],
		modifyArrays: false
	});

	ractive = new Widget({
		el: fixture,
		template: '
{{thing}}
',
		data: {
			thing: new Foo( 'whee!' )
		}
	});

	t.deepEqual( ractive.viewmodel.adaptors, [ Ractive.adaptors.foo ] );
	t.htmlEqual( fixture.innerHTML, '
whee!
' );
});

test( 'Regression test for #798', function ( t ) {
	var ClassA, ClassB, ractive;

	ClassB = function () {};
	ClassA = function () {};
	ClassA.prototype.resources = new ClassB();

	ractive = new Ractive({
		el: fixture,
		template: '<widget attr="{{item.resources}}"/>',
		data: { item: new ClassA() },
		components: {
			widget: Ractive.extend({})
		}
	});

	t.ok( ractive.findComponent('widget').get( 'attr' ) instanceof ClassB );
});

asyncTest( 'Subclass instance oncomplete() handlers can call _super', function ( t ) {
	var Subclass, instance;

	expect( 1 );

	Subclass = Ractive.extend({
		oncomplete: function () {
			return 42;
		}
	});

	instance = new Subclass({
		el: fixture,
		oncomplete: function () {
			t.equal( this._super(), 42 );
			start();
		}
	});
});

test( 'ractive.insert() with triples doesn\'t invoke Yoda (#391)', function ( t ) {
	var ractive = new Ractive({
		el: document.createElement( 'div' ),
		template: '{{{value}}}',
		data: {
			'value': ' you are very puzzled now'
		}
	});

	ractive.insert( fixture );
	t.htmlEqual( fixture.innerHTML, ' you are very puzzled now' );
});

// commenting out. PhantomJS.
// test( '<input value="{{foo}}"> where foo === null should not render a value (#390)', function ( t ) {
// 	var ractive = new Ractive({
// 		el: fixture,
// 		template: '<input value="{{foo}}">',
// 		data: {
// 			foo: null
// 		}
// 	});
//
// 	t.equal( ractive.find( 'input' ).value, '' );
// });

// only run these tests if magic mode is supported
try {
	var obj = {}, _foo;
	Object.defineProperty( obj, 'foo', {
		get: function () {
			return _foo;
		},
		set: function ( value ) {
			_foo = value;
		}
	});

	test( 'Array mutators work when `magic` is `true` (#376)', function ( t ) {
		var ractive, items;

		items = [
			{ name: 'one' },
			{ name: 'two' },
			{ name: 'three' }
		];

		ractive = new Ractive({
			el: fixture,
			template: '{{#items}}{{name}}{{/items}}',
			magic: true,
			data: {
				items: items
			}
		});

		items.push({ name: 'four' });

		t.htmlEqual( fixture.innerHTML, 'onetwothreefour' );
	});

	test( 'Implicit iterators work in magic mode', function ( t ) {
		var ractive, items;

		items = [
			{ name: 'one' },
			{ name: 'two' },
			{ name: 'three' }
		];

		ractive = new Ractive({
			el: fixture,
			template: '{{#.}}{{name}}{{/.}}',
			magic: true,
			data: items
		});

		t.htmlEqual( fixture.innerHTML, 'onetwothree' );

		items[2].name = 'threefourfive';
		t.htmlEqual( fixture.innerHTML, 'onetwothreefourfive' );
	});

	obj.foo = 'bar';
} catch ( err ) {
	// do nothing
}

test( 'Foo.extend(Bar), where both Foo and Bar are Ractive instances, returns on object that inherits from Foo and Bar', function ( t ) {
	var Human, Spider, Spiderman, spiderman;

	Human = Ractive.extend({
		template: '
type: {{type}}
',

		talk: function () {
			return 'hello';
		}
	});

	Spider = Ractive.extend({
		// registries
		data: {
			type: 'arachnid'
		},

		// defaults
		lazy: true,

		// methods
		climb: function () {
			return 'climbing';
		},

		talk: function () {
			return this._super() + ' my name is Peter Parker';
		}
	});

	Spiderman = Human.extend( Spider );

	spiderman = new Spiderman({
		el: fixture
	});

	t.htmlEqual( fixture.innerHTML, '
type: arachnid
' );
	t.ok( spiderman.lazy );
	t.equal( spiderman.climb(), 'climbing' );
	t.equal( spiderman.talk(), 'hello my name is Peter Parker' );
});

test( 'Regression test for #460', function ( t ) {
	var items, ractive, baz;

	items = [
		{ desc: 'foo' },
		{ desc: 'bar' },
		{ desc: 'baz' }
	]

	ractive = new Ractive({
		el: fixture,
		template: '{{#items}}
{{desc}}:{{missing[data]}}
{{/items}}',
		data: { items: items }
	});

	ractive.pop( 'items' ).then( baz => {
		ractive.push( 'items', { desc: 'baz' });
		t.htmlEqual( fixture.innerHTML, '
foo:

bar:

baz:
' );
	});

	t.htmlEqual( fixture.innerHTML, '
foo:

bar:
' );
});

test( 'Regression test for #457', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '{{#step.current == step.current}}
{{foo}}
{{/step.current == step.current}}'
	});

	ractive.set({
		"foo": "bar",
		"step": {
			"current": 2
		}
	});
	t.ok( true );
});

if ( Ractive.svg ) {
	test( 'Case-sensitive conditional SVG attribute', t => {
		var ractive = new Ractive({
			el: fixture,
			template: '<svg {{vb}}></svg>',
			data: { vb: 'viewBox="0 0 100 100"' }
		});

		t.equal( ractive.find( 'svg' ).getAttribute( 'viewBox' ), '0 0 100 100' );
	});
}

test( 'Custom delimiters apply to partials (#601)', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '([#items:i])([>foo])([/items])',
		partials: { foo: '([a])' },
		data: { items: [{a:0},{a:1}] },
		delimiters: [ '([', '])' ],
		tripleDelimiters: [ '([[', ']])' ]
	});

	t.htmlEqual( fixture.innerHTML, '01')
});

test( 'Rendering to an element, if `append` is false, causes any existing instances to be torn down', function ( t ) {
	var ractive1, ractive2;

	expect( 2 );

	ractive1 = new Ractive({
		el: fixture,
		template: 'foo'
	});

	ractive1.on( 'teardown', function () {
		t.ok( true );
	});

	ractive2 = new Ractive({
		el: fixture,
		template: 'bar'
	});

	t.htmlEqual( fixture.innerHTML, 'bar' );
});

// This test fails since #816, because evaluators are treated as computed properties.
// Kept here in case we come up with a smart way to have the best of both worlds
/*test( 'Evaluators are not called if their expressions no longer exist (#716)', function ( t ) {
	var ractive, doubled = 0, tripled = 0;

	ractive = new Ractive({
		el: fixture,
		template: '
{{double(foo)}}
{{#bar}}
{{triple(foo)}}
{{/bar}}',
		data: {
			foo: 3,
			double: function ( foo ) {
				doubled += 1;
				return foo * 2;
			},
			triple: function ( foo ) {
				tripled += 1;
				return foo * 3;
			}
		}
	});

	t.equal( doubled, 1 );
	t.equal( tripled, 0 );

	ractive.set({
		foo: 4,
		bar: true
	});

	t.equal( doubled, 2 );
	t.equal( tripled, 1 );

	ractive.set({
		foo: 5,
		bar: false
	});
	t.equal( doubled, 3 );
	t.equal( tripled, 1 );
});*/

test( 'Regression test for #695 (unrendering non-rendered items)', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '{{# { items: nested.items } }}{{#insert}}{{#items}}

{{/items}}{{/insert}}{{/}}',
		decorators: {
			foo: function () { return { teardown: function () {} }; }
		}
	});

	ractive.set({
		nested: {
			items: [0,1,2]
		},
		insert: false
	});

	ractive.set({
		nested: {
			items: [0,1]
		},
		insert: true
	});

	t.ok( true );
});

asyncTest( 'A Promise will be rejected if its callback throws (#759)', function ( t ) {
	var p = new Ractive.Promise( function () {
		throw 'ruh-roh';
	});

	p.then( null, function ( err ) {
		t.equal( err, 'ruh-roh' );
		QUnit.start();
	});
});

asyncTest( 'A Promise will be chained and rejected if its callback throws ', function ( t ) {
	var p = new Ractive.Promise( function (resolve, reject) {
		resolve();
	});

	p.then(function () {
		throw 'ruh-roh';
	}).then( null, function ( err ) {
		t.equal( err, 'ruh-roh' );
		QUnit.start();
	});
});

test( 'Keypaths in ractive.set() can contain wildcards (#784)', function ( t ) {
	var ractive = new Ractive({
		data: {
			array: [
				{ active: true },
				{ active: false },
				{ active: true }
			],
			object: { foo: 1, bar: 2, baz: 3 }
		}
	});

	ractive.set( 'array.*.active', false );
	t.deepEqual( ractive.get( 'array' ), [{ active: false }, { active: false }, { active: false }]);

	ractive.set( 'object.*', 42 );
	t.deepEqual( ractive.get( 'object' ), { foo: 42, bar: 42, baz: 42 });
});

test( 'Wildcard keypaths do not affect array length', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '{{array.length}}',
		data: {
			array: [ 1, 2, 3 ]
		}
	});

	ractive.set( 'array.*', 10 );
	t.deepEqual( ractive.get( 'array.length' ), 3 );
});

test( 'Regression test for #801', function ( t ) {
	var ractive = new Ractive({
		el: document.createElement( 'div' ),
		template: '
{{#(foo !== "bar")}}not bar{{#(foo !== "baz")}}not baz{{/()}}{{/()}}
',
		data: {
			foo: 'baz'
		}
	});

	ractive.set( 'foo', 'bar' );
	t.ok( true );
});

test( 'Regression test for #832', function ( t ) {
	var ractive = new Ractive({
		el: document.createElement( 'div' ),
		template: '{{#if obj[foo].length}}{{#each obj[foo]}}{{this}}{{/each}}{{/if}}',
		data: {
			obj: {
				a: ['x']
			},
			foo: 'a'
		}
	});

	ractive.set( 'foo', 'b' );
	t.ok( true );
});

test( 'Regression test for #857', function ( t ) {
	var ractive = new Ractive({
		el: document.createElement( 'div' ),
		template: '<textarea value="{{foo}}"></textarea>',
		data: {
			foo: 'works'
		}
	});

	t.equal( ractive.find( 'textarea' ).value, 'works' );
});

asyncTest( 'oncomplete handlers are called for lazily-rendered instances (#749)', function ( t ) {
	expect( 1 );

	var ractive = new Ractive({
		template: '
foo
',
		oncomplete: function () {
			t.ok( true );
			ractive.teardown();
			QUnit.start();
		}
	});

	ractive.render( fixture );
});

test( 'Doctype declarations are handled, and the tag name is uppercased (#877)', function ( t ) {
	var ractive = new Ractive({
		template: '<!DOCTYPE html><meta charset="UTF-8"><title>{{title}}</title>{{hello}} World!',
		data: { title: 'hi', hello: 'Hello' }
	});

	t.equal( ractive.toHTML(), '<!DOCTYPE html><meta charset="UTF-8"><title>hi</title>Hello World!' );
});

test( 'Resolvers are torn down (#884)', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: `
			{{#if foo}}
				{{# steps[currentStep] }}
					argh
				{{/}}

			{{/if}}`,
		data: {
			currentStep: 0,
			steps: [{}, {}]
		}
	});

	expect( 0 );

	ractive.set( 'foo', true );
	ractive.set( 'foo', false );
	ractive.set( 'currentStep', 1 );
});

test( 'Regression test for #844', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: `
			{{# steps[currentStep] }}
				{{#if bool}}
					some text

				{{/if}}
			{{/}}
			{{#if currentStep < steps.length - 1 }}
				toggle step: 1
			{{else}}
				toggle step: 0
			{{/if}}`,
		data: {
			currentStep: 0,
			stepsQuantity: 2,
			steps: [{}, {}],
			bool: true
		}
	});

	ractive.set( 'currentStep', null );
	ractive.set( 'currentStep', 1 );

	t.htmlEqual( fixture.innerHTML, 'some text  toggle step: 0' );

	ractive.set( 'currentStep', 0 );
	t.htmlEqual( fixture.innerHTML, 'some text  toggle step: 1' );
});

test( 'Mustaches that re-resolve to undefined behave correctly (#908)', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: `
			{{# steps[currentStep] }}

{{currentStep}}: {{name}}

			{{/}}`,
		data: {
			currentStep: 0,
			steps: [
				{
					name: 'zero'
				},
				{
					name: 'one'
				}
			]
		}
	});

	ractive.set( 'currentStep', null );
	ractive.set( 'currentStep', 1 );

	t.htmlEqual( fixture.innerHTML, '
1: one
' );
});

test( 'Content renders to correct place when subsequent sections have no nodes (#910)', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '{{ >partial}} ',
		partials: {
			partial: `
				{{# steps[currentStep] }}
					before
				{{/}}
				{{#if currentStep !== 1 }}
					after
				{{else}}
					after
				{{/if}}`
		},
		data: {
			currentStep: 0,
			steps: [ true, true ]
		}
	});

	ractive.set( 'currentStep', null );
	ractive.set( 'currentStep', 1 );

	t.htmlEqual( fixture.innerHTML, 'before after' );
});

test( 'Dependants can register more than once without error (#838)', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '{{#if foo}}
{{fn(foo)}}
{{/if}}',
		data: {
			fn: function ( foo ) {
				foo.bar;
				this.get( 'foo' );
				this.get( 'bar' );
			}
		}
	});

	expect( 0 );

	ractive.set( 'foo', {} );
	ractive.set( 'foo', null );
});

test( 'Ractive.extend() with parsed template (#939)', function ( t ) {
	var parsed, Widget, ractive;

	parsed = Ractive.parse( '
{{foo}}
' );
	Widget = Ractive.extend({ template: parsed });

	ractive = new Widget({ data: { foo: 'bar' }});
	t.equal( ractive.toHTML(), '
bar
' );
});

test( 'Regression test for #950', function ( t ) {
	var ractive, select;

	expect( 0 );

	ractive = new Ractive({
		el: fixture,
		template: `
			{{#if editing}}
				<select value="{{selected}}" on-select="done-selecting" on-blur="done-selecting">
					<option disabled>Select:</option>
					{{#each items}}
					<option>{{this}}</option>
					{{/each}}
				</select>
			{{else}}
				<input type="checkbox" checked="{{editing}}"/>
				{{#if selected}}{{selected}}{{else}}Select...{{/if}}
			{{/if}}`,
		data: {
			editing: true,
			items: ["Apples", "Oranges", "Samsungs"]
		}
	});

	ractive.observe('selected', function() {
		ractive.set('editing', false);
	}, { init: false });

	ractive.on('done-selecting', function( event ) {
		ractive.set('editing', false);
	});

	select = ractive.find( 'select' );
	select.focus();
	select.options[2].selected = true;
	simulant.fire( select, 'change' );
});

test( 'Custom delimiters apply to inline partials (#990)', function ( t ) {
	var ractive = new Ractive({
		template: '([#partial a])abc([/partial])',
		delimiters: [ '([', '])' ]
	});

	t.deepEqual( ractive.partials, { a : [ 'abc' ] });
});

asyncTest( 'Regression test for #1019', function ( t ) {
	var ractive, img, int, i;

	ractive = new Ractive({
		el: fixture,
		template: ''
	});

	img = ractive.find( 'img' );

	i = 0;
	int = setInterval( function () {
		if ( img.complete || i++ === 20 ) {
			clearInterval( int );
			t.equal( img.width, 350 );
			QUnit.start();
		}
	}, 100);
});

asyncTest( 'Another regression test for #1019', function ( t ) {
	var ractive, img, int, i;

	ractive = new Ractive({
		el: fixture,
		template: '

'
	});

	img = ractive.find( 'img' );

	i = 0;
	int = setInterval( function () {
		if ( img.complete || i++ === 20 ) {
			clearInterval( int );
			t.equal( img.width, 350 );
			QUnit.start();
		}
	}, 100);
});

test( 'Regression test for #1003', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: `
			{{#unless foo}}y{{/unless}}

			<select value="{{foo}}">
				<option>x</option>
			</select>`
	});

	t.htmlEqual( fixture.innerHTML, '<select><option>x</option></select>' );
});

test( 'Regression test for #1055', function ( t ) {
	var _, ractive;

	_ = {
		bind: function () {
			// do nothing
		},
		uppercase: function ( str ) {
			return str.toUpperCase();
		}
	};

	ractive = new Ractive({
		el: fixture,
		template: '{{_.uppercase(str)}}',
		data: {
			_: _,
			str: 'foo'
		}
	});

	t.htmlEqual( fixture.innerHTML, 'FOO' );
});

test( 'Interpolation of script/style contents can be disabled (#1050)', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '',
		data: { uninterpolated: 'whoops' },
		interpolate: { script: false }
	});

	t.equal( window.TEST_VALUE, '{{uninterpolated}}' );

	try {
		delete window.TEST_VALUE;
	} catch ( err ) {
		window.TEST_VALUE = null; // IE8, sigh
	}
});

test( 'Changing the length of a section has no effect to detached ractives until they are reattached (#1053)', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '{{#if foo}}yes{{else}}no{{/if}}',
		data: {
			foo: true
		}
	});

	ractive.detach();
	ractive.set( 'foo', false );
	t.htmlEqual( fixture.innerHTML, '' );

	ractive.insert( fixture );
	t.htmlEqual( fixture.innerHTML, 'no' );

	ractive = new Ractive({
		el: fixture,
		template: '{{#each letters}}{{this}}{{/each}}',
		data: {
			letters: [ 'a', 'b', 'c' ]
		}
	});

	ractive.detach();
	ractive.push( 'letters', 'd', 'e', 'f' );
	t.htmlEqual( fixture.innerHTML, '' );

	ractive.insert( fixture );
	t.htmlEqual( fixture.innerHTML, 'abcdef' );
});

asyncTest( 'Regression test for #1038', function ( t ) {
		expect( 0 );

	var el, ractive;

	el = document.createElement( 'div' );
	ractive = new Ractive({
		el: el,
		template: `
			{{#with obj}}
				{{#if loading}}
					Loading...
				{{else}}
					{{#error}}
						Error!
					{{/error}}

					Content.
				{{/if}}
			{{/with}}`,
		data: {
			obj: {}
		}
	});

	ractive.set('obj.loading', true);

	setTimeout( function () {
		ractive.set('obj.error', true);
		ractive.set('obj.loading', false);

		QUnit.start();
	}, 100 );
});

test( 'Reference expressions can become invalid after being valid, without breaking (#1106)', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: `
			{{#with items[i]}}
				{{this}}
			{{/with}}`,
		data: {
			items: [ 'a', 'b', 'c', 'd' ]
		}
	});

	ractive.set( 'i', 0 );
	t.htmlEqual( fixture.innerHTML, 'a' );

	ractive.set( 'i', 1 );
	t.htmlEqual( fixture.innerHTML, 'b' );

	ractive.set( 'i', null );
	t.htmlEqual( fixture.innerHTML, '' );
	ractive.set( 'i', 2 );

	t.htmlEqual( fixture.innerHTML, 'c' );
});

test( 'Implicitly-closed elements without closing section tag (#1124)', function ( t ) {
	// this test lives here, not in render.js, due to an awkward quirk with htmlEqual -
	// it corrects malformed HTML before stubbing it
	var ractive = new Ractive({
		el: fixture,
		template: '

one
two
three'
	});

	t.equal( ractive.findAll( 'ul > li' ).length, 3 );

	ractive = new Ractive({
		el: fixture,
		template: '

onetwothree'
	});

	t.equal( ractive.findAll( 'tr > td' ).length, 3 );
});

test( 'Reference expressions used in component parameters teardown properly (#1130)', function ( t ) {

	var ractive = new Ractive({
		el: fixture,
		template: '<widget data="{{foo[bar]}}"/>',
		components: {
			widget: Ractive.extend({})
		},
		data: {
			foo: { a: 'apple', b: 'banana' },
			bar: 'a'
		}
	});

	ractive.teardown();

	t.ok( true );
});

test( 'Regression test for #1166 (spellcheck bug)', function ( t ) {
	var ractive, one, two;

	ractive = new Ractive({
		el: fixture,
		template: '<input class="one" spellcheck="false"><input class="two" spellchecker="false">',
		data: { name: 'world' }
	});

	one = ractive.find( '.one' );
	two = ractive.find( '.two' );

	t.ok( !one.spellcheck );
	t.equal( one.getAttribute( 'spellcheck' ), 'false' );
	t.equal( two.getAttribute( 'spellchecker' ), 'false' );
});

test( '. reference without any implicit or explicit context should resolve to root', t => {
	var ractive = new Ractive({
		el: fixture,
		template: '{{JSON.stringify(.)}}',
		data: { foo: 'bar' }
	});

	t.equal( fixture.innerHTML, JSON.stringify( ractive.viewmodel.value ) );
	ractive.set( 'foo', 'test' );
	t.equal( fixture.innerHTML, JSON.stringify( ractive.viewmodel.value ) );
});

test( 'Nested conditional computations should survive unrendering and rerendering (#1364)', ( t ) => {
	var ractive = new Ractive({
		el: fixture,
		template: '{{#cond}}{{# i === 1 }}1{{/}}{{# i === 2 }}2{{/}}{{/}}',
		data: { i: 1, cond: true }
	});

	t.equal( fixture.innerHTML, '1' );
	ractive.set( 'cond', false );
	ractive.set( 'cond', true );
	ractive.set( 'i', 2 );
	t.equal( fixture.innerHTML, '2' );
});

test( 'DOCTYPE declarations are stringified correctly', function ( t ) {
	var template = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
	t.equal( new Ractive({ template: template }).toHTML(), template );
});

test( 'Ractive.getNodeInfo returns correct keypath, index, and ractive info', t => {
	var ractive = new Ractive({
		el: fixture,
		template: '
<foo />
{{#bars:i}}b<foo />{{/}}{{#baz}}{{#bat}}
hello
{{/}}{{/}}',
		components: {
			foo: Ractive.extend({
				template: 'foo'
			})
		},
		data: {
			bars: [1, 2],
			baz: { bat: {} }
		}
	});

	let div = Ractive.getNodeInfo( ractive.find( 'div' ) );
	let p = Ractive.getNodeInfo( ractive.find( 'p' ) );
	let [b1, b2] = ractive.findAll( 'b' ).map( n => Ractive.getNodeInfo( n ) );
	let [span1, span2, span3] = ractive.findAll( 'span' ).map( n => Ractive.getNodeInfo( n ) );
	let [foo1, foo2, foo3] = ractive.findAllComponents( 'foo' );

	t.equal( div.ractive, ractive );
	t.equal( span1.ractive, foo1 );
	t.equal( span2.ractive, foo2 );
	t.equal( span3.ractive, foo3 );

	t.equal( span1.keypath, '' );
	t.equal( span2.keypath, '' );
	t.equal( span3.keypath, '' );
	t.equal( b1.keypath, 'bars.0' );
	t.equal( b2.keypath, 'bars.1' );

	t.equal( span1.index.i, undefined );
	t.equal( span2.index.i, 0 );
	t.equal( span3.index.i, 1 );
	t.equal( b1.index.i, 0 );
	t.equal( b2.index.i, 1 );

	t.equal( p.keypath, 'baz.bat' );
});

test( 'Boolean attributes are added/removed based on unstringified fragment value', function ( t ) {
	var ractive, button;

	ractive = new Ractive({
		el: fixture,
		template: '<button disabled="{{foo}}"></button>',
		data: {
			foo: true
		}
	});

	button = ractive.find( 'button' );
	t.ok( button.disabled );

	ractive.set( 'foo', false );
	t.ok( !button.disabled );
});

test( 'input[type=range] values are respected regardless of attribute order (#1621)', function ( t ) {
	var ractive = new Ractive({
		el: fixture,
		template: '<input type="range" min="0" max="200" value="150"/>'
	});

	t.equal( ractive.find( 'input' ).value, 150 );

	ractive = new Ractive({
		el: fixture,
		template: '<input value="150" type="range" min="0" max="200"/>'
	});

	t.equal( ractive.find( 'input' ).value, 150 );
});

test( 'regression test for #1630', function ( t ) {
	var ractive = new Ractive();

	var obj = { foo: 'bar' };
	obj.constructor = obj.constructor;

	ractive.set( obj );
	t.equal( ractive.get( 'foo' ), 'bar' );
	t.equal( ractive.get( 'constructor' ), obj.constructor );
});

test( 'Ractive can be instantiated without `new`', t => {
	t.ok( Ractive() instanceof Ractive );

	var Subclass = Ractive.extend();
	t.ok( Subclass() instanceof Subclass );
	t.ok( Subclass() instanceof Ractive );
});

test( 'multiple pattern keypaths can be set simultaneously (#1319)', t => {
	let ractive = new Ractive({
		data: {
			foo: [ 1, 2, 3 ],
			bar: [ 4, 5, 6 ]
		}
	});

	ractive.set({
		'foo.*': 5,
		'bar.*': 10
	});

	t.deepEqual( ractive.get( 'foo' ), [ 5, 5, 5 ] );
	t.deepEqual( ractive.get( 'bar' ), [ 10, 10, 10 ] );
});

asyncTest( 'Promise.all works with non-promises (#1642)', t => {
	// this test is redundant in browsers that support Promise natively
	Ractive.Promise.all([ Ractive.Promise.resolve( 1 ), 2 ]).then( values => {
		t.deepEqual( values, [ 1, 2 ]);
		QUnit.start();
	});
});

if ( hasUsableConsole ) {
	test( 'Ractive.DEBUG can be changed', t => {
		let DEBUG = Ractive.DEBUG;
		Ractive.DEBUG = false;

		let warn = console.warn;
		console.warn = () => t.ok( false );

		expect( 0 );
		new Ractive({ template: '{{>thisWouldNormallyWarn}}' });

		Ractive.DEBUG = DEBUG;
		console.warn = warn;
	});
}

// Is there a way to artificially create a FileList? Leaving this commented
// out until someone smarter than me figures out how
// test( '{{#each}} iterates over a FileList (#1220)', t => {
// 	var input, files, ractive;

// 	input = document.createElement( 'input' );
// 	input.type = 'file';
// 	files = input.files;

// 	files[0] = { name: 'one.txt' };
// 	files[1] = { name: 'two.txt' };
// 	files[2] = { name: 'three.txt' };

// 	ractive = new Ractive({
// 		el: fixture,
// 		template: '{{#each files}}
{{name}}
{{/each}}',
// 		data: { files: files }
// 	});

// 	t.htmlEqual( fixture.innerHTML, '
one.txt

two.txt

three.txt
' );
// });

// These tests run fine in the browser but not in PhantomJS. WTF I don't even.
// Anyway I can't be bothered to figure it out right now so I'm just commenting
// these out so it will build

/*test( 'Components with two-way bindings set parent values on initialisation', function ( t ) {
	var Dropdown, ractive;

	Dropdown = Ractive.extend({
		template: '<select value="{{value}}">{{#options}}<option value="{{this}}">{{ this[ display ] }}</option>{{/options}}</select>'
	});

	ractive = new Ractive({
		el: fixture,
		template: '
Select an option:
<dropdown options="{{numbers}}" value="{{number}}" display="word"/>
Selected: {{number.digit}}
',
		data: {
			numbers: [
				{ word: 'one', digit: 1 },
				{ word: 'two', digit: 2 },
				{ word: 'three', digit: 3 },
				{ word: 'four', digit: 4 }
			]
		},
		components: {
			dropdown: Dropdown
		}
	});

	t.deepEqual( ractive.get( 'number' ), { word: 'one', digit: 1 });
});

{
	name: 'Tearing down expression mustaches and recreating them does\'t throw errors',
	test: function () {
		var ractive;

		ractive = new Ractive({
			el: fixture,
			template: '{{#condition}}{{( a+b )}} {{( a+b )}} {{( a+b )}}{{/condition}}',
			data: { a: 1, b: 2, condition: true }
		});

		equal( fixture.innerHTML, '3 3 3' );

		ractive.set( 'condition', false );
		equal( fixture.innerHTML, '' );

		ractive.set( 'condition', true );
		equal( fixture.innerHTML, '3 3 3' );
	}
},
{
	name: 'Updating an expression section doesn\'t throw errors',
	test: function () {
		var ractive, array;

		array = [{ foo: 1 }, { foo: 2 }, { foo: 3 }, { foo: 4 }, { foo: 5 }];

		ractive = new Ractive({
			el: fixture,
			template: '{{#( array.slice( 0, 3 ) )}}{{foo}}{{/()}}',
			data: { array: array }
		});

		equal( fixture.innerHTML, '123' );

		array.push({ foo: 6 });
		equal( fixture.innerHTML, '123' );

		array.unshift({ foo: 0 });
		equal( fixture.innerHTML, '012' );

		ractive.set( 'array', [] );
		equal( array._ractive, undefined );
		equal( fixture.innerHTML, '' );

		ractive.set( 'array', array );
		ok( array._ractive );
		equal( fixture.innerHTML, '012' );
	}
},
{
	name: 'Updating a list section with child list expressions doesn\'t throw errors',
	test: function () {
		var ractive, array;

		array = [
			{ foo: [ 1, 2, 3, 4, 5 ] },
			{ foo: [ 2, 3, 4, 5, 6 ] },
			{ foo: [ 3, 4, 5, 6, 7 ] },
			{ foo: [ 4, 5, 6, 7, 8 ] },
			{ foo: [ 5, 6, 7, 8, 9 ] }
		];

		ractive = new Ractive({
			el: fixture,
			template: '{{#array}}
{{#( foo.slice( 0, 3 ) )}}{{.}}{{/()}}
{{/array}}',
			data: { array: array }
		});

		equal( fixture.innerHTML, '
123

234

345

456

567
' );

		array.push({ foo: [ 6, 7, 8, 9, 10 ] });
		equal( fixture.innerHTML, '
123

234

345

456

567

678
' );

		array.unshift({ foo: [ 0, 1, 2, 3, 4 ] });
		equal( fixture.innerHTML, '
012

123

234

345

456

567

678
' );

		ractive.set( 'array', [] );
		equal( array._ractive, undefined );
		equal( fixture.innerHTML, '' );

		ractive.set( 'array', array );
		ok( array._ractive );
		equal( fixture.innerHTML, '
012

123

234

345

456

567

678
' );
	}
}*/


text:
package com.couchbase.lite.support;

import com.couchbase.lite.Database;
import com.couchbase.lite.Manager;
import com.couchbase.lite.auth.AuthenticatorImpl;
import com.couchbase.lite.auth.Authenticator;
import com.couchbase.lite.util.Log;
import com.couchbase.lite.util.URIUtils;
import com.couchbase.lite.util.Utils;

import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.ClientParamsStack;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class RemoteRequest implements Runnable {

    private static final int MAX_RETRIES = 2;
    private static final int RETRY_DELAY_MS = 10 * 1000;

    protected ScheduledExecutorService workExecutor;
    protected final HttpClientFactory clientFactory;
    protected String method;
    protected URL url;
    protected Object body;
    protected Authenticator authenticator;
    protected RemoteRequestCompletionBlock onPreCompletion;
    protected RemoteRequestCompletionBlock onCompletion;
    protected RemoteRequestCompletionBlock onPostCompletion;
    private int retryCount;
    private Database db;

    protected Map<String, Object> requestHeaders;

    public RemoteRequest(ScheduledExecutorService workExecutor,
                         HttpClientFactory clientFactory, String method, URL url,
                         Object body, Database db, Map<String, Object> requestHeaders, RemoteRequestCompletionBlock onCompletion) {
        this.clientFactory = clientFactory;
        this.method = method;
        this.url = url;
        this.body = body;
        this.onCompletion = onCompletion;
        this.workExecutor = workExecutor;
        this.requestHeaders = requestHeaders;
        this.db = db;

    }

    @Override
    public void run() {

        HttpClient httpClient = clientFactory.getHttpClient();

        ClientConnectionManager manager = httpClient.getConnectionManager();

        HttpUriRequest request = createConcreteRequest();

        preemptivelySetAuthCredentials(httpClient);

        request.addHeader("Accept", "multipart/related, application/json");

        addRequestHeaders(request);

        setBody(request);

        executeRequest(httpClient, request);

    }

    protected void addRequestHeaders(HttpUriRequest request) {
        for (String requestHeaderKey : requestHeaders.keySet()) {
            request.addHeader(requestHeaderKey, requestHeaders.get(requestHeaderKey).toString());
        }
    }

    public void setOnPostCompletion(RemoteRequestCompletionBlock onPostCompletion) {
        this.onPostCompletion = onPostCompletion;
    }

    public void setOnPreCompletion(RemoteRequestCompletionBlock onPreCompletion) {
        this.onPreCompletion = onPreCompletion;
    }

    protected HttpUriRequest createConcreteRequest() {
        HttpUriRequest request = null;
        if (method.equalsIgnoreCase("GET")) {
            request = new HttpGet(url.toExternalForm());
        } else if (method.equalsIgnoreCase("PUT")) {
            request = new HttpPut(url.toExternalForm());
        } else if (method.equalsIgnoreCase("POST")) {
            request = new HttpPost(url.toExternalForm());
        }
        return request;
    }

    protected void setBody(HttpUriRequest request) {
        // set body if appropriate
        if (body != null && request instanceof HttpEntityEnclosingRequestBase) {
            byte[] bodyBytes = null;
            try {
                bodyBytes = Manager.getObjectMapper().writeValueAsBytes(body);
            } catch (Exception e) {
                Log.e(Log.TAG_REMOTE_REQUEST, "Error serializing body of request", e);
            }
            ByteArrayEntity entity = new ByteArrayEntity(bodyBytes);
            entity.setContentType("application/json");
            ((HttpEntityEnclosingRequestBase) request).setEntity(entity);
        }
    }

    /**
     *  Set Authenticator for BASIC Authentication
     */
    public void setAuthenticator(Authenticator authenticator) {
        this.authenticator = authenticator;
    }

    /**
     * Retry this remote request, unless we've already retried MAX_RETRIES times
     *
     * NOTE: This assumes all requests are idempotent, since even though we got an error back, the
     * request might have succeeded on the remote server, and by retrying we'd be issuing it again.
     * PUT and POST requests aren't generally idempotent, but the ones sent by the replicator are.
     *
     * @return true if going to retry the request, false otherwise
     */
    protected boolean retryRequest() {
        if (retryCount >= MAX_RETRIES) {
            return false;
        }
        workExecutor.schedule(this, RETRY_DELAY_MS, TimeUnit.MILLISECONDS);
        retryCount += 1;
        Log.d(Log.TAG_REMOTE_REQUEST, "Will retry in %d ms", RETRY_DELAY_MS);
        return true;
    }

    protected void executeRequest(HttpClient httpClient, HttpUriRequest request) {
        Object fullBody = null;
        Throwable error = null;
        HttpResponse response = null;

        try {
            response = httpClient.execute(request);

            // add in cookies to global store
            try {
                if (httpClient instanceof DefaultHttpClient) {
                    DefaultHttpClient defaultHttpClient = (DefaultHttpClient)httpClient;
                    this.clientFactory.addCookies(defaultHttpClient.getCookieStore().getCookies());
                }
            } catch (Exception e) {
                Log.e(Log.TAG_REMOTE_REQUEST, "Unable to add in cookies to global store", e);
            }

            StatusLine status = response.getStatusLine();
            if (Utils.isTransientError(status) && retryRequest()) {
                return;
            }

            if (status.getStatusCode() >= 300) {
                Log.e(Log.TAG_REMOTE_REQUEST, "Got error status: %d for %s.  Reason: %s", status.getStatusCode(), request, status.getReasonPhrase());
                error = new HttpResponseException(status.getStatusCode(),
                        status.getReasonPhrase());
            } else {
                HttpEntity temp = response.getEntity();
                if (temp != null) {
                    InputStream stream = null;
                    try {
                        stream = temp.getContent();
                        fullBody = Manager.getObjectMapper().readValue(stream,
                                Object.class);
                    } finally {
                        try {
                            stream.close();
                        } catch (IOException e) {
                        }
                    }
                }
            }
        } catch (ClientProtocolException e) {
            Log.e(Log.TAG_REMOTE_REQUEST, "client protocol exception", e);
            error = e;
        } catch (IOException e) {
            Log.e(Log.TAG_REMOTE_REQUEST, "io exception", e);
            error = e;
            // Treat all IOExceptions as transient, per:
            // http://hc.apache.org/httpclient-3.x/exception-handling.html
            if (retryRequest()) {
                return;
            }
        }
        respondWithResult(fullBody, error, response);
    }

    protected void preemptivelySetAuthCredentials(HttpClient httpClient) {
        boolean isUrlBasedUserInfo = false;

        String userInfo = url.getUserInfo();
        if (userInfo != null) {
            isUrlBasedUserInfo = true;
        } else {
            if (authenticator != null) {
                AuthenticatorImpl auth = (AuthenticatorImpl) authenticator;
                userInfo = auth.authUserInfo();
            }
        }

        if (userInfo != null) {
            if (userInfo.contains(":") && !userInfo.trim().equals(":")) {
                String[] userInfoElements = userInfo.split(":");
                String username = isUrlBasedUserInfo ? URIUtils.decode(userInfoElements[0]): userInfoElements[0];
                String password = isUrlBasedUserInfo ? URIUtils.decode(userInfoElements[1]): userInfoElements[1];
                final Credentials credentials = new UsernamePasswordCredentials(username, password);

                if (httpClient instanceof DefaultHttpClient) {
                    DefaultHttpClient dhc = (DefaultHttpClient) httpClient;
                    HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() {
                        @Override
                        public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
                            AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
                            if (authState.getAuthScheme() == null) {
                                authState.setAuthScheme(new BasicScheme());
                                authState.setCredentials(credentials);
                            }
                        }
                    };
                    dhc.addRequestInterceptor(preemptiveAuth, 0);
                }
            } else {
                Log.w(Log.TAG_REMOTE_REQUEST, "RemoteRequest Unable to parse user info, not setting credentials");
            }
        }
    }

    public void respondWithResult(final Object result, final Throwable error, final HttpResponse response) {
        if (workExecutor != null) {
            workExecutor.submit(new Runnable() {

                @Override
                public void run() {
                    try {
                        if (onPreCompletion != null) {
                            onPreCompletion.onCompletion(response, error);
                        }
                        onCompletion.onCompletion(result, error);
                        if (onPostCompletion != null) {
                            onPostCompletion.onCompletion(response, error);
                        }
                    } catch (Exception e) {
                        // don't let this crash the thread
                        Log.e(Log.TAG_REMOTE_REQUEST,
                                "RemoteRequestCompletionBlock throw Exception",
                                e);
                    }
                }
            });
        } else {
            Log.e(Log.TAG_REMOTE_REQUEST, "Work executor was null!");
        }
    }

}

redpajama_set_name: RedPajamaGithub


text:
#ifndef Q3DATABROWSER_H
#define Q3DATABROWSER_H

#include <QtGui/qwidget.h>
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
#include <QtSql/qsql.h>
#include <QtSql/qsqlindex.h>
#include <Qt3Support/q3sqlcursor.h>
#include <QtSql/qsqlerror.h>

QT_BEGIN_HEADER

QT_BEGIN_NAMESPACE

QT_MODULE(Qt3Support)

#ifndef QT_NO_SQL_VIEW_WIDGETS

class Q3SqlForm;
class Q3DataBrowserPrivate;

class Q_COMPAT_EXPORT Q3DataBrowser : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(bool boundaryChecking READ boundaryChecking WRITE setBoundaryChecking)
    Q_PROPERTY(QString filter READ filter WRITE setFilter)
    Q_PROPERTY(QStringList sort READ sort WRITE setSort)
    Q_PROPERTY(bool confirmEdits READ confirmEdits WRITE setConfirmEdits)
    Q_PROPERTY(bool confirmInsert READ confirmInsert WRITE setConfirmInsert)
    Q_PROPERTY(bool confirmUpdate READ confirmUpdate WRITE setConfirmUpdate)
    Q_PROPERTY(bool confirmDelete READ confirmDelete WRITE setConfirmDelete)
    Q_PROPERTY(bool confirmCancels READ confirmCancels WRITE setConfirmCancels)
    Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly)
    Q_PROPERTY(bool autoEdit READ autoEdit WRITE setAutoEdit)

public:
    Q3DataBrowser(QWidget* parent=0, const char* name=0, Qt::WindowFlags fl = 0);
    ~Q3DataBrowser();

    enum Boundary {
        Unknown,
        None,
        BeforeBeginning,
        Beginning,
        End,
        AfterEnd
    };

    Boundary boundary();
    void setBoundaryChecking(bool active);
    bool boundaryChecking() const;

    void setSort(const QSqlIndex& sort);
    void setSort(const QStringList& sort);
    QStringList  sort() const;
    void setFilter(const QString& filter);
    QString filter() const;
    virtual void setSqlCursor(Q3SqlCursor* cursor, bool autoDelete = false);
    Q3SqlCursor* sqlCursor() const;
    virtual void setForm(Q3SqlForm* form);
    Q3SqlForm* form();

    virtual void setConfirmEdits(bool confirm);
    virtual void setConfirmInsert(bool confirm);
    virtual void setConfirmUpdate(bool confirm);
    virtual void setConfirmDelete(bool confirm);
    virtual void setConfirmCancels(bool confirm);
    bool confirmEdits() const;
    bool confirmInsert() const;
    bool confirmUpdate() const;
    bool confirmDelete() const;
    bool confirmCancels() const;

    virtual void setReadOnly(bool active);
    bool isReadOnly() const;
    virtual void setAutoEdit(bool autoEdit);
    bool autoEdit() const;

    virtual bool seek(int i, bool relative = false);

Q_SIGNALS:
    void firstRecordAvailable(bool available);
    void lastRecordAvailable(bool available);
    void nextRecordAvailable(bool available);
    void prevRecordAvailable(bool available);

    void currentChanged(const QSqlRecord* record);
    void primeInsert(QSqlRecord* buf);
    void primeUpdate(QSqlRecord* buf);
    void primeDelete(QSqlRecord* buf);
    void beforeInsert(QSqlRecord* buf);
    void beforeUpdate(QSqlRecord* buf);
    void beforeDelete(QSqlRecord* buf);
    void cursorChanged(Q3SqlCursor::Mode mode);

public Q_SLOTS:
    virtual void refresh();

    virtual void insert();
    virtual void update();
    virtual void del();

    virtual void first();
    virtual void last();
    virtual void next();
    virtual void prev();

    virtual void readFields();
    virtual void writeFields();
    virtual void clearValues();

    void updateBoundary();

protected:
    virtual bool insertCurrent();
    virtual bool updateCurrent();
    virtual bool deleteCurrent();
    virtual bool currentEdited();

    virtual QSql::Confirm confirmEdit(QSql::Op m);
    virtual QSql::Confirm confirmCancel(QSql::Op m);

    virtual void handleError(const QSqlError& error);

private:
    typedef bool (Q3SqlCursor::*Nav)();
    bool preNav();
    void postNav(bool primeUpd);
    void nav(Nav nav);
    Q3DataBrowserPrivate* d;

    Q_DISABLE_COPY(Q3DataBrowser)
};

#endif // QT_NO_SQL_VIEW_WIDGETS

QT_END_NAMESPACE

QT_END_HEADER

#endif // Q3DATABROWSER_H


text:
<?php

  $config['web']['errorMessages'] = array(
    'ERROR_MODULE_NOT_FOUND' => 'Módulo no encontrado.',
    'ERROR_LOGIN_DEFAULT' => 'Usuario / Contraseña incorrecta.',
    'ERROR_NO_SESSION' => 'No has iniciado sesión.',
    'ERROR_SIGNUP' => 'Ha ocurrido un error en su registro. Vuelva a intentar.',
    'ERROR_SIGNUP_USER_EXISTS' => 'El username seleccionado ya existe.',
    'ERROR_LOGIN_NULL' => 'Ha ocurrido un error. Vuelva a intentar.',
    'ERROR_TUTORSHIP_NOT_FOUND' => 'Ayudantía inexistente.',
    'ERROR_CREATE_TUTORSHIP' => 'La ayudantía no pudo ser registrada.',
    'ERROR_NO_ATTENDANCE' => 'No se pudo confirmar su asistencia.',
    'ERROR_ALREADY_ATTENDED' => 'Ya has confirmado tu asistencia anteriormente.',
    'ERROR_REVIEW' => 'No se pudo ingresar su comentario. Intente más tarde.'
  );

  $config['web']['formMessages'] = array(
    'MESSAGE_LOGIN_OK' => 'Login exitoso.',
    'MESSAGE_LOGOUT_OK' => 'Has cerrado sesión exitosamente.',
    'MESSAGE_SIGNUP_OK' => 'Su cuenta ha sido creada exitosamente.',
    'MESSAGE_CREATE_TUTORSHIP_OK' => 'Ayudantía registrada con éxito.',
    'MESSAGE_ATTENDANCE_OK' => 'Su asistencia ha sido procesada.',
    'MESSAGE_REVIEW_OK' => 'Su comentario ha sido ingresado.',
    'MESSAGE_CHANGEPASSWORD_OK' => 'Su contraseña ha sido cambiada.'
  );

  $config['web']['messageTypes'] = array(
    'MESSAGE_TYPE_POSITIVE' => 'positive',
    'MESSAGE_TYPE_NEGATIVE' => 'negative',
    'MESSAGE_TYPE_WARNING' => 'warning',
    'MESSAGE_TYPE_INFO' => 'info'
  );

  $config['web']['status'] = array(
    'STATUS_ACTIVE' => 1
  );

  DEFINE('ERROR_MODULE_NOT_FOUND', $config['web']['errorMessages']['ERROR_MODULE_NOT_FOUND']);
  DEFINE('ERROR_LOGIN_DEFAULT', $config['web']['errorMessages']['ERROR_LOGIN_DEFAULT']);
  DEFINE('ERROR_NO_SESSION', $config['web']['errorMessages']['ERROR_NO_SESSION']);
  DEFINE('ERROR_SIGNUP', $config['web']['errorMessages']['ERROR_SIGNUP']);
  DEFINE('ERROR_LOGIN_NULL', $config['web']['errorMessages']['ERROR_LOGIN_NULL']);
  DEFINE('ERROR_SIGNUP_USER_EXISTS', $config['web']['errorMessages']['ERROR_SIGNUP_USER_EXISTS']);
  DEFINE('ERROR_TUTORSHIP_NOT_FOUND', $config['web']['errorMessages']['ERROR_TUTORSHIP_NOT_FOUND']);
  DEFINE('ERROR_CREATE_TUTORSHIP', $config['web']['errorMessages']['ERROR_CREATE_TUTORSHIP']);
  DEFINE('ERROR_NO_ATTENDANCE', $config['web']['errorMessages']['ERROR_NO_ATTENDANCE']);
  DEFINE('ERROR_ALREADY_ATTENDED', $config['web']['errorMessages']['ERROR_ALREADY_ATTENDED']);
  DEFINE('ERROR_REVIEW', $config['web']['errorMessages']['ERROR_REVIEW']);

  DEFINE('MESSAGE_LOGIN_OK', $config['web']['formMessages']['MESSAGE_LOGIN_OK']);
  DEFINE('MESSAGE_LOGOUT_OK', $config['web']['formMessages']['MESSAGE_LOGOUT_OK']);
  DEFINE('MESSAGE_SIGNUP_OK', $config['web']['formMessages']['MESSAGE_SIGNUP_OK']);
  DEFINE('MESSAGE_ATTENDANCE_OK', $config['web']['formMessages']['MESSAGE_ATTENDANCE_OK']);
  DEFINE('MESSAGE_REVIEW_OK', $config['web']['formMessages']['MESSAGE_REVIEW_OK']);
  DEFINE('MESSAGE_CREATE_TUTORSHIP_OK', $config['web']['formMessages']['MESSAGE_CREATE_TUTORSHIP_OK']);
  DEFINE('MESSAGE_CHANGEPASSWORD_OK', $config['web']['formMessages']['MESSAGE_CHANGEPASSWORD_OK']);

  DEFINE('MESSAGE_TYPE_POSITIVE', $config['web']['messageTypes']['MESSAGE_TYPE_POSITIVE']);
  DEFINE('MESSAGE_TYPE_NEGATIVE', $config['web']['messageTypes']['MESSAGE_TYPE_NEGATIVE']);
  DEFINE('MESSAGE_TYPE_WARNING', $config['web']['messageTypes']['MESSAGE_TYPE_WARNING']);
  DEFINE('MESSAGE_TYPE_INFO', $config['web']['messageTypes']['MESSAGE_TYPE_INFO']);

  DEFINE('STATUS_ACTIVE', $config['web']['status']['STATUS_ACTIVE']);

?>