text:
<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing,
  software distributed under the License is distributed on an
  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  KIND, either express or implied.  See the License for the
  specific language governing permissions and limitations
  under the License.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-resources-plugin-it-profile-override</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>

  <build>
    <resources>
      <resource>
        <directory>src/main/resources/test</directory>
        <filtering>false</filtering>
      </resource>
    </resources>
    <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>@project.version@</version>
          <configuration>
            <overwrite>true</overwrite>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
  <profiles>
    <profile>
      <id>production</id>
      <build>
        <resources>
          <resource>
            <directory>src/main/resources/production</directory>
            <filtering>false</filtering>
          </resource>
        </resources>
      </build>
    </profile>
  </profiles>
</project>


text:
using FlixSharp.Helpers.OAuth;
using FlixSharp.Holders.RottenTomatoes;
using FlixSharp.Queries.RottenTomatoes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FlixSharp.Helpers.RottenTomatoes
{
    internal class UrlBuilder
    {
        public static String SearchUrl(String SearchTerm, Int32 Limit = 10, Int32 Page = 1)
        {
            return String.Format(Constants.SearchUrl, Login.ConsumerKey, OAuthHelpers.Encode(SearchTerm), Limit, Page);
        }

        public static String BoxOfficeUrl(String Country, Int32 Limit = 10)
        {
            return String.Format(Constants.BoxOfficeUrl, Login.ConsumerKey, Country, Limit);
        }
        public static String InTheatersUrl(String Country, Int32 Limit = 10, Int32 Page = 1)
        {
            return String.Format(Constants.InTheatersUrl, Login.ConsumerKey, Country, Limit, Page);
        }
        public static String OpeningMoviesUrl(String Country, Int32 Limit = 10)
        {
            return String.Format(Constants.OpeningMoviesUrl, Login.ConsumerKey, Country, Limit);
        }
        public static String UpcomingMoviesUrl(String Country, Int32 Limit = 10, Int32 Page = 1)
        {
            return String.Format(Constants.UpcomingMoviesUrl, Login.ConsumerKey, Country, Limit, Page);
        }

        public static String TopRentalsUrl(String Country, Int32 Limit = 10)
        {
            return String.Format(Constants.TopRentalsUrl, Login.ConsumerKey, Country, Limit);
        }
        public static String CurrentReleaseDVDsUrl(String Country, Int32 Limit = 10, Int32 Page = 1)
        {
            return String.Format(Constants.CurrentReleaseDVDsUrl, Login.ConsumerKey, Country, Limit, Page);
        }
        public static String NewReleaseDVDsUrl(String Country, Int32 Limit = 10, Int32 Page = 1)
        {
            return String.Format(Constants.NewReleaseDVDsUrl, Login.ConsumerKey, Country, Limit, Page);
        }
        public static String UpcomingDVDsUrl(String Country, Int32 Limit = 10, Int32 Page = 1)
        {
            return String.Format(Constants.UpcomingDVDsUrl, Login.ConsumerKey, Country, Limit, Page);
        }

        public static String MoviesInfoUrl(String Id)
        {
            return String.Format(Constants.MoviesInfoUrl, Login.ConsumerKey, Id);
        }

        public static String CastInfoUrl(String Id)
        {
            return String.Format(Constants.CastInfoUrl, Login.ConsumerKey, Id);
        }
        public static String ClipsUrl(String Id)
        {
            return String.Format(Constants.ClipsUrl, Login.ConsumerKey, Id);
        }
        public static String ReviewsUrl(String Id, ReviewType ReviewType = ReviewType.All, String Country = "us", Int32 Limit = 10, Int32 Page = 1)
        {
            return String.Format(Constants.ReviewsUrl, Login.ConsumerKey, Id,
                ReviewType.ToString().ToLower(), Country, Limit, Page);
        }
        public static String SimilarMoviesUrl(String Id, Int32 Limit = 5)
        {
            return String.Format(Constants.SimilarMoviesUrl, Login.ConsumerKey, Id, Limit);
        }

        public static String MovieAliasUrl(String Id, AlternateIdType IdType)
        {
            return String.Format(Constants.MovieAliasUrl, Login.ConsumerKey, Id, IdType.ToString().ToLower());
        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
Language.create(short: "ara",      full: "Arabic", enabled: false)
Language.create(short: "aze", 	   full: "Azerbauijani", enabled: false)
Language.create(short: "bul", 	   full: "Bulgarian", enabled: false)
Language.create(short: "cat", 	   full: "Catalan", enabled: false)
Language.create(short: "ces", 	   full: "Czech", enabled: false)
Language.create(short: "chi_sim",  full: "Simplified Chinese", enabled: false)
Language.create(short: "chi_tra",  full: "Traditional Chinese", enabled: false)
Language.create(short: "chr", 	   full: "Cherokee", enabled: false)
Language.create(short: "dan", 	   full: "Danish", enabled: false)
Language.create(short: "dan-frak", full: "Danish (Fraktur)", enabled: false)
Language.create(short: "deu", 	   full: "German", enabled: false)
Language.create(short: "ell", 	   full: "Greek", enabled: false)
Language.create(short: "eng", 	   full: "English", enabled: true)
Language.create(short: "enm", 	   full: "Old English", enabled: false)
Language.create(short: "epo", 	   full: "Esperanto", enabled: false)
Language.create(short: "est", 	   full: "Estonian", enabled: false)
Language.create(short: "fin", 	   full: "Finnish", enabled: false)
Language.create(short: "fra", 	   full: "French", enabled: false)
Language.create(short: "frm", 	   full: "Old French", enabled: false)
Language.create(short: "glg", 	   full: "Galician", enabled: false)
Language.create(short: "heb", 	   full: "Hebrew", enabled: false)
Language.create(short: "hin", 	   full: "Hindi", enabled: false)
Language.create(short: "hrv", 	   full: "Croation", enabled: false)
Language.create(short: "hun", 	   full: "Hungarian", enabled: false)
Language.create(short: "ind", 	   full: "Indonesian", enabled: false)
Language.create(short: "ita", 	   full: "Italian", enabled: false)
Language.create(short: "jpn", 	   full: "Japanese", enabled: false)
Language.create(short: "kor", 	   full: "Korean", enabled: false)
Language.create(short: "lav", 	   full: "Latvian", enabled: false)
Language.create(short: "lit", 	   full: "Lithuanian", enabled: false)
Language.create(short: "nld", 	   full: "Dutch", enabled: false)
Language.create(short: "nor", 	   full: "Norwegian", enabled: false)
Language.create(short: "pol", 	   full: "Polish", enabled: false)
Language.create(short: "por", 	   full: "Portuguese", enabled: false)
Language.create(short: "ron", 	   full: "Romanian", enabled: false)
Language.create(short: "rus", 	   full: "Russian", enabled: false)
Language.create(short: "slk", 	   full: "Slovakian", enabled: false)
Language.create(short: "slv", 	   full: "Slovenian", enabled: false)
Language.create(short: "sqi", 	   full: "Albanian", enabled: false)
Language.create(short: "spa", 	   full: "Spanish", enabled: true)
Language.create(short: "srp", 	   full: "Serbian", enabled: false)
Language.create(short: "swe", 	   full: "Swedish", enabled: true)
Language.create(short: "tam", 	   full: "Tamil", enabled: false)
Language.create(short: "tel", 	   full: "Telugu", enabled: false)
Language.create(short: "tgl", 	   full: "Tagalog", enabled: false)
Language.create(short: "tha", 	   full: "Thai", enabled: false)
Language.create(short: "tur", 	   full: "Turkish", enabled: false)
Language.create(short: "ukr", 	   full: "Ukrainian", enabled: false)
Language.create(short: "vie", 	   full: "Vietnamese", enabled: false)

# add the phases of document conversion lifecycle
Phase.create(id: 1, name: "uploaded")
Phase.create(id: 2, name: "preprocessing")
Phase.create(id: 3, name: "reprocessing")
Phase.create(id: 4, name: "ready")
Phase.create(id: 5, name: "extracting")
Phase.create(id: 6, name: "extracted")

#Tyndale.create(short: "", full: "Afrikaans", enabled: true)
#Tyndale.create(short: "", full: "Albanian", enabled: true)
#Tyndale.create(short: "", full: "Arabic", enabled: true)
#Tyndale.create(short: "", full: "Belarusian", enabled: true)
#Tyndale.create(short: "", full: "Bulgarian", enabled: true)
#Tyndale.create(short: "", full: "Catalan", enabled: true)
#Tyndale.create(short: "", full: "Simplified_chinese", enabled: true)
#Tyndale.create(short: "", full: "Traditional_chinese", enabled: true)
#Tyndale.create(short: "", full: "Croatian", enabled: true)
#Tyndale.create(short: "", full: "Czech", enabled: true)
#Tyndale.create(short: "", full: "Danish", enabled: true)
#Tyndale.create(short: "", full: "Dutch", enabled: true)
#Tyndale.create(short: "", full: "English", enabled: true)
#Tyndale.create(short: "", full: "Estonian", enabled: true)
#Tyndale.create(short: "", full: "Filipino", enabled: true)
#Tyndale.create(short: "", full: "Finnish", enabled: true)
#Tyndale.create(short: "", full: "French", enabled: true)
#Tyndale.create(short: "", full: "Galician", enabled: true)
#Tyndale.create(short: "", full: "German", enabled: true)
#Tyndale.create(short: "", full: "Greek", enabled: true)
#Tyndale.create(short: "", full: "Haitian_creole", enabled: true)
#Tyndale.create(short: "", full: "Hebrew", enabled: true)
#Tyndale.create(short: "", full: "Hindi", enabled: true)
#Tyndale.create(short: "", full: "Hungarian", enabled: true)
#Tyndale.create(short: "", full: "Icelandic", enabled: true)
#Tyndale.create(short: "", full: "Indonesian", enabled: true)
#Tyndale.create(short: "", full: "Irish", enabled: true)
#Tyndale.create(short: "", full: "Italian", enabled: true)
#Tyndale.create(short: "", full: "Japanese", enabled: true)
#Tyndale.create(short: "", full: "Latvian", enabled: true)
#Tyndale.create(short: "", full: "Lithuanian", enabled: true)
#Tyndale.create(short: "", full: "Macedonian", enabled: true)
#Tyndale.create(short: "", full: "Malay", enabled: true)
#Tyndale.create(short: "", full: "Maltese", enabled: true)
#Tyndale.create(short: "", full: "Norwegian", enabled: true)
#Tyndale.create(short: "", full: "Persian", enabled: true)
#Tyndale.create(short: "", full: "Polish", enabled: true)
#Tyndale.create(short: "", full: "Portuguese", enabled: true)
#Tyndale.create(short: "", full: "Romanian", enabled: true)
#Tyndale.create(short: "", full: "Russian", enabled: true)
#Tyndale.create(short: "", full: "Serbian", enabled: true)
#Tyndale.create(short: "", full: "Slovak", enabled: true)
#Tyndale.create(short: "", full: "Slovenian", enabled: true)
#Tyndale.create(short: "", full: "Spanish", enabled: true)
#Tyndale.create(short: "", full: "Swahili", enabled: true)
#Tyndale.create(short: "", full: "Swedish", enabled: true)
#Tyndale.create(short: "", full: "Thai", enabled: true)
#Tyndale.create(short: "", full: "Turkish", enabled: true)
#Tyndale.create(short: "", full: "Ukrainian", enabled: true)
#Tyndale.create(short: "", full: "Vietnamese", enabled: true)
#Tyndale.create(short: "", full: "Welsh", enabled: true)
#Tyndale.create(short: "", full: "Yiddish", enabled: true)


text:
import angular from "./../angular-fix";
import getNgModelNodesFallback from "./get-ng-model-nodes-fallback";
// Utility functions
export default (node, skip, query) => {
    const selectorNot = angular.isString(skip) ? `:not(${skip})` : "";
    const skipNot = ":not([formly-skip-ng-model-attrs-manipulator])";
    if (!query)
        query = `[ng-model]${selectorNot}${skipNot}, [data-ng-model]${selectorNot}${skipNot}`;
    try {
        return node.querySelectorAll(query);
    } catch (e) {
        //this code is needed for IE8, as it does not support the CSS3 ':not' selector
        //it should be removed when IE8 support is dropped
        return getNgModelNodesFallback(node, skip);
    }
};


text:
Small python utility for generating tags tables for large projects.

This is just a small utility that I use for indexing large codebases.

In this case, the Unreal 4 Engine. It should be pretty self-explanatory
from examination of the .conf file. To run, all is needed is to run
python tagbank.py and the indexes are updated. The tag files are named
after the headings in the .conf file, so the example will generate tag
files named UE4Editor.TAGS, UE4Developer.TAGS and UE4Runtime.TAGS

Dependencies: (installable with pip)

* python-ctags3
* watchdog


text:
package org.kie.camel.component.cxf;

import org.apache.camel.test.junit4.CamelSpringTestSupport;
import org.drools.compiler.kproject.ReleaseIdImpl;
import org.junit.Test;
import org.kie.api.builder.ReleaseId;
import org.kie.spring.InternalKieSpringUtils;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.File;

public class CxfRestTest extends CamelSpringTestSupport {

    @Override
    protected AbstractXmlApplicationContext createApplicationContext() {
        return (AbstractXmlApplicationContext) InternalKieSpringUtils.getSpringContext(new ReleaseIdImpl("kie-camel", "test-spring", "0001"),
                                                                                CxfRestTest.class.getResource("/org/kie/camel/component/CxfRsSpring.xml"));
    }

    @Test
    public void test1() throws Exception {
        String cmd = "";
        cmd += "<batch-execution lookup=\"ksession1\">\n";
        cmd += "  <insert out-identifier=\"salaboy\">\n";
        cmd += "      <org.kie.pipeline.camel.Person>\n";
        cmd += "         <name>salaboy</name>\n";
        cmd += "      </org.kie.pipeline.camel.Person>\n";
        cmd += "   </insert>\n";
        cmd += "   <fire-all-rules/>\n";
        cmd += "</batch-execution>\n";

        Object object = this.context.createProducerTemplate().requestBody( "direct://http",
                                                                           cmd );
        System.out.println( object );
    }

}


text:
#region License

#endregion

using System;
using System.Reflection;
using AopAlliance.Aop;
using Spring.Aop.Framework;
using Spring.Aop.Support;

namespace Spring.Transaction.Interceptor
{
	///
	/// Advisor driven by a <see cref="Spring.Transaction.Interceptor.ITransactionAttributeSource"/>,
    /// used to exclude a general advice <see cref="IAdvice"/> from methods that
	/// are non-transactional.
	///
	/// <remarks>
	/// <para>
	/// To put it another way, use this advisor when you would like to associate other AOP
	/// advice based on the pointcut specified by declarative transaction demarcation,
	/// attibute based or otherwise.
	/// </para>
	///

	/// Because the AOP framework caches advice calculations, this is normally
    /// faster than just letting the <see cref="AopAlliance.Intercept.IInterceptor"/>
	/// run and find out itself that it has no work to do.
	///

	/// </remarks>
	/// <author>Mark Pollack (.NET)</author>
	[Serializable]
	public class DefaultTransactionAttributeSourceAdvisor : StaticMethodMatcherPointcutAdvisor
	{
		private ITransactionAttributeSource _transactionAttributeSource;

		///
		/// Creates a new instance of the
        /// <see cref="Spring.Transaction.Interceptor.DefaultTransactionAttributeSourceAdvisor"/> class.
		///
        public DefaultTransactionAttributeSourceAdvisor(ITransactionAttributeSource transactionAttributeSource, IAdvice advice)
			: base( advice )
		{
            if (transactionAttributeSource == null)
			{
                throw new AopConfigException("Cannot construct a DefaultTransactionAttributeSourceAdvisor if " +
					"TransactionAttributeSource is null.");
			}
            _transactionAttributeSource = transactionAttributeSource;
		}

		///
		/// Tests the input method to see if it's covered by the advisor.
		///
		/// <param name="method">The method to match.</param>
		/// <param name="targetClass">The <see cref="System.Type"/> to match against.</param>
		/// <returns>
		/// True if the supplied <paramref name="method"/> is covered by the advisor.
		/// </returns>
		public override bool Matches(MethodInfo method, Type targetClass)
		{
		    return ( _transactionAttributeSource.ReturnTransactionAttribute( (MethodInfo)method, targetClass ) != null);
		}
	}
}


text:
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using NUnit.Framework;

namespace NServiceBus.AcceptanceTests.Exceptions
{
    static class StackTraceAssert
    {
        public static void StartsWith(string expected, string actual)
        {
            if (actual == null)
            {
                Assert.Fail();
            }
            else
            {
                var cleanStackTrace = CleanStackTrace(actual);

                var reader = new StringReader(cleanStackTrace);

                var stringBuilder = new StringBuilder();
                while (true)
                {
                    var actualLine = reader.ReadLine();
                    if (actualLine == null)
                    {
                        break;
                    }
                    if (expected.Contains(actualLine))
                    {
                        stringBuilder.AppendLine(actualLine);
                    }
                }

                try
                {
                    actual = stringBuilder.ToString().TrimEnd();
                    Assert.AreEqual(actual, expected);
                }
                catch (Exception)
                {
                    Trace.WriteLine(cleanStackTrace);
                    throw;
                }
            }
        }
        static string CleanStackTrace(string stackTrace)
        {
            if (stackTrace== null)
            {
                return string.Empty;
            }
            using (var stringReader = new StringReader(stackTrace))
            {
                var stringBuilder = new StringBuilder();
                while (true)
                {
                    var line = stringReader.ReadLine();
                    if (line == null)
                    {
                        break;
                    }

                    stringBuilder.AppendLine(line.Split(new[]
                    {
                        " in "
                    }, StringSplitOptions.RemoveEmptyEntries).First().Trim());
                }
                return stringBuilder.ToString().Trim();
            }
        }
    }
}


text:
Swarm, the synchronized object system, addresses every event or
entity by its *specifier*. A specifier is built of tokens (ids)
identifying various aspects of an event/object. Ids are somewhat
analogous to Mongo's Object Ids, uniquely specifying the time of
an event and its source (author). Objects are identified by the
event of their creation (birth stamps).

## Identifiers

An id is approximately 12 bytes long, represented either as a
6-symbol Unicode string or as a 18-symbol Base32 string. An id
contains:

- 30-bit timestamp (seconds since 1 Jan 2010)
- 15-bit sequence number to separate same-second events
- 30-bit source (author) id
- 15-bit session number to separate sessions of the same user
  (e.g. several browser windows)

Sometimes we use *retrofitted* ids which are simply unique
strings without any internal structure. For example, class field
names are encoded as ids. Their base32 representations are
supposed to be human-readable. Simply random ids may also be used
sometimes.

## Specifiers

Ids are *words* of our addressing system. Specifiers are
meaningful *sentences* having their nouns, verbs and adjectives.
To distinguish those we use "quants", one-char special symbols
that provide the context for an id that follows. Valid quants are
/#.,:! and $. For example,

    /ClassName#object_id.fieldName

points at a particular field of a particular object and

    /ClassName#object_id!rev_id

addresses a particular revision of that object.  Formally,
specifiers are tuples of quant-prefixed ids.  Specifier is an
extremely handy formalism for the purpose of data/event
storage/serialization. It provides non-ambiguous addressing and
nearly-binary storage efficiency. The Swarm pumps data around as
a stream of small incremental changes. As an extremely concise
addressing scheme, Specifiers both enable and optimize of that
process.

## Forms: raw and parsed

A specifier in its raw form is a Unicode string consisting of
7-symbol tokens. Each token is a quant followed by 6-symbol id.
If you know what I mean:

    /([\/\#\.\,\:\!\$])([0-\u802f]{6})/g

That form is compact and simple, albeit not that human readable.
A specifier string may be parsed into an object. The general rule
is to parse specifiers on demand to avoid unnecessary work. A
semi-parsed Spec object looks like:

    {
        type,        //  /
        object,      //  #
        field,       //  .
        key,         //  ,
        method,      //  :
        version,     //  !
        base,        //  $
        cache,       // the original specifier string
        cache32      // base32 spec string
    }

Each field is the corresponding id of the specifier represented
as a 7-symbol Unicode string or an empty string if there is none.
In some special cases a field may contain multiple concatenated
ids.  Then, every id may be parsed further into an object:

    {
        q,   // quant int
        ts,  // timestamp int
        seq, // sequence number int
        src, // source int
        ssn, // session int
        cache,  // the id string
        cache32 // base32 id string
    }

Capitalization of the Base32 string depends on the quant.
CollectionNames are given in CamelCase, methodNames in
lowerCamelcase, other ids are undrscore_separated. Note that
RFC4648 Base32 encoding lacks '0', '1', '8' and '9'. Field names
and class names must be valid ids in the Base32 form. Otherwise,
they are not picked up by Swarm and not synchronized.  Both Spec
and ID objects have the usual toString() method returning the
compact Unicode representation. Its twin toString32() method
returns the Base32 representation. The latter is mostly useful
for debugging as Base32 strings are (simply) three times longer.

A reader may ask why don't we always use Base32 identifiers.
Well, Unicode lets us use 6 char long identifiers and 20-30 char
long typical specifiers, which are rather acceptable. Base32 is
human-readable on one hand, but on the other hand 18-char ids and
70-char specifiers are totally incomprehensible and simply
ridiculous.  Often, it is easier to visually remember a couple of
hierogliphs than a 6 symbol long Base32 string. The other option
is to use spec.toString32() when debugging.

Parsed objects are (generally) supposed to be immutable. In case
you modify such an object please nullify its cache field; or
else toString will return stale data.

## API

Three core methods Swarm installs on every synched object are:

    on(spec,fn)   // start listening to an object
    set(spec,val) // set field value
    off(spec,fn)  // stop listening

Other methods are:

    once(spec,fn)     // listen to an event once
    diff(spec,obj)    // check for changes
    get(spec,default) // get field value

General life cycle

    Peer.on() // returns the object
    Peer.off() // garbage collection

Navigating the graph

Collections

## The generalized spec-val signature

A careful reader probably noted that most of our API methods have
the same (spec,val) signature. The signature is my effort to
generalize popular set/get and on/listener conventions. In the
most general meaning, these two arguments express some change to
the state. The former argument (spec) provides the scope for the
change, while the latter keeps the actual values.

In its most full form, the spec-val pair looks like:

    swarm.set('/type#object!version', {
        '.fieldA': 'valueA',
        '.fieldB': 'valueB'
    });

What we have here is the scope specifier mentioning a collection,
object and version, and a map of specifier-value pairs
mentioning values for particular fields of the object.

All other forms are considered shortcuts. For example,

    var spec = new Spec('x','.');
    spec.parse().field.toString32() === 'x';
    obj.set(spec, 1);
    obj.get('x') === 1; // true
    obj.set({'x':2});
    obj.get(spec) === 2;  // true

A string provided as the first argument is considered to be some
id in the Base32 form unless it matches the specifier regex
(starts with a quant etc). The type of an id is derived from the
context; the "set" call assumes the id is a field name.

Also, Swarm provides convenience methods for every field detected
on a new object, like

    Swarm.extend(SampleObject);
    var obj = new SampleObject(); // has x
    obj.setX(1) === 1;
    obj.getX() === obj.get('x');

Callback functions use the same two arguments:

    obj.on('x',function(spec,val){
        console.log(val);   // outputs '1'
    }).setX(1);

It is possible to do "bundled" set calls:

    obj.set('',{x:1,y:2}) // '' counts as a spec

The classic convention is also supported:

    obj.set({x:1,y:2})  // anon object isnt a Spec

The bundled set call is even preferred as it generates one
version while a sequence of set calls generates a sequence of
versions.

Given the variety forms to provide a specifier we encourage you
to secure any specifier arguments using

        Spec.as(specInSomeForm, defaultQuant, scope)

Thus e.g.

        Spec.as('#000000', '', '!111111').version === '!111111';
        Spec.as('x', '.').field === ".00G000";
        Spec.as('key', '.').field === ".00⣈000"; //scary Unicode
        Spec.as('fieldName', '.').field === ".0Øᆓ0=ƴ";
        Spec.as('fieldName', '.').parse('.')
            .field.toString32() === 'fieldName'
        // single ids as well:
        ID.as('fieldName', '.').toString32() === 'fieldName'

Note that the Unicode string form of IDs can contain exotic
characters.

The best form of a lesson is an example, so:

    // initialize it first

    function Mouse () {
        this.x = this.y = 0;
    };
    Peer.extend (Mouse, '_Mouse', {
        x: 'coordx',
        y: 'coordy'
    });
    Mouse.prototype._tid === '/_Mouse';
    var peer = new Peer(client_id);
    var mickey = peer.on('/_Mouse#mickey');

    // move Mickey to {x:10,y:0}

    mickey.set('x', 10);
        // mouse.spec() is the scope, new version id is generated
    Mouse.set('#mickey.coordx', 10);
        // 00G000 is the Unicode form for 'x'. Yes, it's longer.
    mickey.set({x: 10});
    mickey.set('x',10);
    mickey.setX(10);
    peer.set("#mickey", {x: 10});
        // #mickey should be open already, otherwise:
    peer.set('/_Mouse#mickey.coordx', 10);
        // that was a blind write
    mickey.set({'.coordx': 10});

All of the above examples have nearly identical effects. The
resulting on-the-wire diff looks like:

    { "/_Mouse#mickey.coordx!ಕ⎷P00D": 10 }

You may listen to Mickey's progress:

    var xkey = Mouse.prototype._fids['x']; // "coordx"

    mickey.on('x', function(spec,val) {
        spec = Spec.as(spec); // unnecessary
        spec.field===xkey; // true
        console.log("Eek! A mouse! It's moving!",val);
    });

Swarm: sync'em all!


text:
package org.apache.felix.dm.impl;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.felix.dm.Component;
import org.apache.felix.dm.ComponentDeclaration;
import org.apache.felix.dm.ComponentDependencyDeclaration;
import org.apache.felix.dm.ComponentStateListener;
import org.apache.felix.dm.Dependency;
import org.apache.felix.dm.DependencyActivation;
import org.apache.felix.dm.DependencyManager;
import org.apache.felix.dm.DependencyService;
import org.apache.felix.dm.InvocationUtil;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

/**
 * Component implementation.
 *
 * @author Felix Project Team
 */
public class ComponentImpl implements Component, DependencyService, ComponentDeclaration, Comparable {
    private static final Class[] VOID = new Class[] {};
	private static final ServiceRegistration NULL_REGISTRATION;
    private static final ComponentStateListener[] SERVICE_STATE_LISTENER_TYPE = new ComponentStateListener[] {};
    private static long HIGHEST_ID = 0;

    private final Object SYNC = new Object();
    private final BundleContext m_context;
    private final DependencyManager m_manager;
    private final long m_id;

    // configuration (static)
    private String m_callbackInit;
    private String m_callbackStart;
    private String m_callbackStop;
    private String m_callbackDestroy;
    private Object m_serviceName;
    private Object m_implementation;
    private Object m_callbackInstance;

    // configuration (dynamic, but does not affect state)
    private Dictionary m_serviceProperties;

    // configuration (dynamic, and affects state)
    private ArrayList m_dependencies = new ArrayList();

    // runtime state (calculated from dependencies)
    private State m_state;

    // runtime state (changes because of state changes)
    private Object m_serviceInstance;
    private volatile ServiceRegistration m_registration;
    private boolean m_isBound;
    private boolean m_isInstantiated;

    // service state listeners
    private final List m_stateListeners = new ArrayList();

    // work queue
    private final SerialExecutor m_executor = new SerialExecutor();

    // instance factory
	private Object m_instanceFactory;
	private String m_instanceFactoryCreateMethod;

	// composition manager
	private Object m_compositionManager;
	private String m_compositionManagerGetMethod;
	private Object m_compositionManagerInstance;

	// internal logging
    private final Logger m_logger;

    private Map m_autoConfig = new HashMap();
    private Map m_autoConfigInstance = new HashMap();

    private boolean m_isStarted = false;

    public ComponentImpl(BundleContext context, DependencyManager manager, Logger logger) {
        synchronized (VOID) {
            m_id = HIGHEST_ID++;
        }
    	m_logger = logger;
        m_state = new State((List) m_dependencies.clone(), false, false, false);
        m_context = context;
        m_manager = manager;
        m_callbackInit = "init";
        m_callbackStart = "start";
        m_callbackStop = "stop";
        m_callbackDestroy = "destroy";
        m_implementation = null;
        m_autoConfig.put(BundleContext.class, Boolean.TRUE);
        m_autoConfig.put(ServiceRegistration.class, Boolean.TRUE);
        m_autoConfig.put(DependencyManager.class, Boolean.TRUE);
        m_autoConfig.put(Component.class, Boolean.TRUE);
    }

    private void calculateStateChanges() {
        // see if any of the things we did caused a further change of state
        State oldState, newState;
        synchronized (m_dependencies) {
            oldState = m_state;
            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
            m_state = newState;
        }
        calculateStateChanges(oldState, newState);
    }

    private void calculateStateChanges(final State oldState, final State newState) {
        if (oldState.isInactive() && (newState.isTrackingOptional())) {
            m_executor.enqueue(new Runnable() {
                public void run() {
                    activateService(newState);
                }});
        }
        if (oldState.isInactive() && (newState.isWaitingForRequired())) {
            m_executor.enqueue(new Runnable() {
                public void run() {
                    startTrackingRequired(newState);
                }});
        }
        if (oldState.isWaitingForRequired() && newState.isTrackingOptional()) {
            m_executor.enqueue(new Runnable() {
                public void run() {
                    activateService(newState);
                }});
        }
        if ((oldState.isWaitingForRequired()) && newState.isInactive()) {
            m_executor.enqueue(new Runnable() {
                public void run() {
                    stopTrackingRequired(oldState);
                }});
        }
        if (oldState.isTrackingOptional() && newState.isWaitingForRequiredInstantiated()) {
            m_executor.enqueue(new Runnable() {
                public void run() {
                    // TODO as far as I can see there is nothing left to do here
                    // unbindService(newState);
                }});
        }
        if (oldState.isTrackingOptional() && newState.isWaitingForRequired()) {
            m_executor.enqueue(new Runnable() {
                public void run() {
                    deactivateService(oldState);
                }});
        }
        if (oldState.isTrackingOptional() && newState.isBound()) {
            m_executor.enqueue(new Runnable() {
                public void run() {
                    bindService(newState);
                }});
        }
        if (oldState.isTrackingOptional() && newState.isInactive()) {
            m_executor.enqueue(new Runnable() {
                public void run() {
                    deactivateService(oldState);
                    stopTrackingRequired(oldState);
                }});
        }
        if (oldState.isWaitingForRequiredInstantiated() && newState.isWaitingForRequired()) {
            m_executor.enqueue(new Runnable() {
                public void run() {
                    deactivateService(oldState);
                }});
        }
        if (oldState.isWaitingForRequiredInstantiated() && newState.isInactive()) {
            m_executor.enqueue(new Runnable() {
                public void run() {
                    deactivateService(oldState);
                    stopTrackingRequired(oldState);
                }});
        }
        if (oldState.isWaitingForRequiredInstantiated() && newState.isBound()) {
            m_executor.enqueue(new Runnable() {
                public void run() {
                    bindService(newState);
                }});
        }
        if (oldState.isBound() && newState.isWaitingForRequiredInstantiated()) {
            m_executor.enqueue(new Runnable() {
                public void run() {
                    unbindService(oldState);
                }});
        }
        if (oldState.isBound() && newState.isWaitingForRequired()) {
            m_executor.enqueue(new Runnable() {
                public void run() {
                    unbindService(oldState);
                    deactivateService(oldState);
                }});
        }
        if (oldState.isBound() && newState.isInactive()) {
            m_executor.enqueue(new Runnable() {
                public void run() {
                    unbindService(oldState);
                    deactivateService(oldState);
                    stopTrackingRequired(oldState);
                }});
        }
        m_executor.execute();
    }

    // TODO fix code duplication between add(Dependency) and add(List)
    public Component add(final Dependency dependency) {
    	State oldState, newState;
        synchronized (m_dependencies) {
        	oldState = m_state;
            m_dependencies.add(dependency);
        }

        // if we're inactive, don't do anything, otherwise we might want to start
        // the dependency
        if (!oldState.isInactive()) {
            // if the dependency is required, it should be started regardless of the state
            // we're in
            if (dependency.isRequired()) {
                ((DependencyActivation) dependency).start(this);
            }
            else {
                // if the dependency is optional, it should only be started if we're in
                // bound state
                if (oldState.isBound()) {
                    ((DependencyActivation) dependency).start(this);
                }
            }
        }

        synchronized (m_dependencies) {
            oldState = m_state;
            // starting the dependency above might have triggered another state change, so
            // we have to fetch the current state again
            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
            m_state = newState;
        }
        calculateStateChanges(oldState, newState);
        return this;
    }

    public Component add(List dependencies) {
        State oldState, newState;
        synchronized (m_dependencies) {
            oldState = m_state;
            for (int i = 0; i < dependencies.size(); i++) {
                m_dependencies.add(dependencies.get(i));
            }
        }

        // if we're inactive, don't do anything, otherwise we might want to start
        // the dependencies
        if (!oldState.isInactive()) {
            for (int i = 0; i < dependencies.size(); i++) {
                Dependency dependency = (Dependency) dependencies.get(i);
                // if the dependency is required, it should be started regardless of the state
                // we're in
                if (dependency.isRequired()) {
                    ((DependencyActivation) dependency).start(this);
                }
                else {
                    // if the dependency is optional, it should only be started if we're in
                    // bound state
                    if (oldState.isBound()) {
                        ((DependencyActivation) dependency).start(this);
                    }
                }
            }
        }

        synchronized (m_dependencies) {
            oldState = m_state;
            // starting the dependency above might have triggered another state change, so
            // we have to fetch the current state again
            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
            m_state = newState;
        }
        calculateStateChanges(oldState, newState);
        return this;
    }

    public Component remove(Dependency dependency) {
    	State oldState, newState;
        synchronized (m_dependencies) {
        	oldState = m_state;
            m_dependencies.remove(dependency);
        }
        if (oldState.isAllRequiredAvailable() || ((oldState.isWaitingForRequired() || oldState.isWaitingForRequiredInstantiated()) && dependency.isRequired())) {
        	((DependencyActivation) dependency).stop(this);
        }
        synchronized (m_dependencies) {
            // starting the dependency above might have triggered another state change, so
            // we have to fetch the current state again
            oldState = m_state;
            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
            m_state = newState;
        }
        calculateStateChanges(oldState, newState);
        return this;
    }

    public List getDependencies() {
        synchronized (m_dependencies) {
            return (List) m_dependencies.clone();
        }
    }

    public ServiceRegistration getServiceRegistration() {
        return m_registration;
    }

    public Object getService() {
        return m_serviceInstance;
    }

    public Component getServiceInterface() {
        return this;
    }

    public void dependencyAvailable(final Dependency dependency) {
    	State oldState, newState;
        synchronized (m_dependencies) {
        	oldState = m_state;
            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
            m_state = newState;
        }
        if (newState.isAllRequiredAvailable() || newState.isWaitingForRequiredInstantiated()) {
        	updateInstance(dependency);
        }
        calculateStateChanges(oldState, newState);
    }

    public void dependencyChanged(final Dependency dependency) {
    	State state;
        synchronized (m_dependencies) {
        	state = m_state;
        }
        if (state.isAllRequiredAvailable()) {
        	updateInstance(dependency);
        }
    }

    public void dependencyUnavailable(final Dependency dependency) {
    	State oldState, newState;
        synchronized (m_dependencies) {
        	oldState = m_state;
            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
            m_state = newState;
        }
        if (newState.isAllRequiredAvailable()) {
        	updateInstance(dependency);
        }
        calculateStateChanges(oldState, newState);
    }

    public synchronized void start() {
    	if (!m_isStarted) {
    	    m_isStarted = true;
	        State oldState, newState;
	        synchronized (m_dependencies) {
	            oldState = m_state;
	            newState = new State((List) m_dependencies.clone(), true, m_isInstantiated, m_isBound);
	            m_state = newState;
	        }
	        calculateStateChanges(oldState, newState);
    	}
    }

    public synchronized void stop() {
        if (m_isStarted) {
            m_isStarted = false;
	        State oldState, newState;
	        synchronized (m_dependencies) {
	            oldState = m_state;
	            newState = new State((List) m_dependencies.clone(), false, m_isInstantiated, m_isBound);
	            m_state = newState;
	        }
	        calculateStateChanges(oldState, newState);
    	}
    }

    public synchronized Component setInterface(String serviceName, Dictionary properties) {
	    ensureNotActive();
	    m_serviceName = serviceName;
	    m_serviceProperties = properties;
	    return this;
	}

	public synchronized Component setInterface(String[] serviceName, Dictionary properties) {
	    ensureNotActive();
	    m_serviceName = serviceName;
	    m_serviceProperties = properties;
	    return this;
	}

	public synchronized Component setCallbacks(String init, String start, String stop, String destroy) {
	    ensureNotActive();
	    m_callbackInit = init;
	    m_callbackStart = start;
	    m_callbackStop = stop;
	    m_callbackDestroy = destroy;
	    return this;
	}

    public synchronized Component setCallbacks(Object instance, String init, String start, String stop, String destroy) {
        ensureNotActive();
        m_callbackInstance = instance;
        m_callbackInit = init;
        m_callbackStart = start;
        m_callbackStop = stop;
        m_callbackDestroy = destroy;
        return this;
    }

	public synchronized Component setImplementation(Object implementation) {
	    ensureNotActive();
	    m_implementation = implementation;
	    return this;
	}

	public synchronized Component setFactory(Object factory, String createMethod) {
	    ensureNotActive();
		m_instanceFactory = factory;
		m_instanceFactoryCreateMethod = createMethod;
		return this;
	}

	public synchronized Component setFactory(String createMethod) {
		return setFactory(null, createMethod);
	}

	public synchronized Component setComposition(Object instance, String getMethod) {
	    ensureNotActive();
		m_compositionManager = instance;
		m_compositionManagerGetMethod = getMethod;
		return this;
	}

	public synchronized Component setComposition(String getMethod) {
		return setComposition(null, getMethod);
	}

	public String toString() {
	    return this.getClass().getSimpleName() + "[" + m_serviceName + " " + m_implementation + "]";
	}

	public synchronized Dictionary getServiceProperties() {
	    if (m_serviceProperties != null) {
	        return (Dictionary) ((Hashtable) m_serviceProperties).clone();
	    }
	    return null;
	}

	public synchronized Component setServiceProperties(Dictionary serviceProperties) {
	    m_serviceProperties = serviceProperties;
	    if ((m_registration != null) && (m_serviceName != null)) {
	        m_registration.setProperties(calculateServiceProperties());
	    }
	    return this;
	}

	// service state listener methods
	public void addStateListener(ComponentStateListener listener) {
    	synchronized (m_stateListeners) {
		    m_stateListeners.add(listener);
    	}
    	// when we register as a listener and the service is already started
    	// make sure we invoke the right callbacks so the listener knows
    	State state;
    	synchronized (m_dependencies) {
    		state = m_state;
    	}
    	if (state.isBound()) {
    		listener.starting(this);
    		listener.started(this);
    	}
	}

	public void removeStateListener(ComponentStateListener listener) {
    	synchronized (m_stateListeners) {
    		m_stateListeners.remove(listener);
    	}
	}

	public void removeStateListeners() {
    	synchronized (m_stateListeners) {
    		m_stateListeners.clear();
    	}
	}

	private void stateListenersStarting() {
		ComponentStateListener[] list = getListeners();
		for (int i = 0; i < list.length; i++) {
		    try {
		        list[i].starting(this);
		    }
		    catch (Throwable t) {
		        m_logger.log(Logger.LOG_ERROR, "Error invoking listener starting method.", t);
		    }
		}
	}

	private void stateListenersStarted() {
        ComponentStateListener[] list = getListeners();
        for (int i = 0; i < list.length; i++) {
            try {
                list[i].started(this);
            }
            catch (Throwable t) {
                m_logger.log(Logger.LOG_ERROR, "Error invoking listener started method.", t);
            }
        }
    }

    private void stateListenersStopping() {
        ComponentStateListener[] list = getListeners();
        for (int i = 0; i < list.length; i++) {
            try {
                list[i].stopping(this);
            }
            catch (Throwable t) {
                m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopping method.", t);
            }
        }
    }

    private void stateListenersStopped() {
        ComponentStateListener[] list = getListeners();
        for (int i = 0; i < list.length; i++) {
            try {
                list[i].stopped(this);
            }
            catch (Throwable t) {
                m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopped method.", t);
            }
        }
    }

	private ComponentStateListener[] getListeners() {
		synchronized (m_stateListeners) {
			return (ComponentStateListener[]) m_stateListeners.toArray(SERVICE_STATE_LISTENER_TYPE);
		}
	}

    private void activateService(State state) {
        String init;
        synchronized (this) {
            init = m_callbackInit;
        }
        // service activation logic, first we initialize the service instance itself
        // meaning it is created if necessary and the bundle context is set
        initService();
        // now is the time to configure the service, meaning all required
        // dependencies will be set and any callbacks called
        configureService(state);
        // flag that our instance has been created
        m_isInstantiated = true;
        // then we invoke the init callback so the service can further initialize
        // itself
        invoke(init);
        // see if any of this caused further state changes
        calculateStateChanges();
    }

    private void bindService(State state) {
        String start;
        synchronized (this) {
            start = m_callbackStart;
        }

        // configure service with extra-dependencies which might have been added from init() method.
        configureServiceWithExtraDependencies(state);
        // inform the state listeners we're starting
        stateListenersStarting();
        // invoke the start callback, since we're now ready to be used
        invoke(start);
        // start tracking optional services
        startTrackingOptional(state);
        // register the service in the framework's service registry
        registerService();
        // inform the state listeners we've started
        stateListenersStarted();
    }

    private void configureServiceWithExtraDependencies(State state) {
        Iterator i = state.getDependencies().iterator();
        while (i.hasNext()) {
            Dependency dependency = (Dependency) i.next();
            if (dependency.isAutoConfig() && dependency.isInstanceBound()) {
                configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
            }
        }
    }

    private void unbindService(State state) {
        String stop;
        synchronized (this) {
            stop = m_callbackStop;
        }
        // service deactivation logic, first inform the state listeners
        // we're stopping
        stateListenersStopping();
        // then, unregister the service from the framework
        unregisterService();
        // stop tracking optional services
        stopTrackingOptional(state);
        // invoke the stop callback
        invoke(stop);
        // inform the state listeners we've stopped
        stateListenersStopped();
    }

    private void deactivateService(State state) {
        String destroy;
        synchronized (this) {
            destroy = m_callbackDestroy;
        }
        // flag that our instance was destroyed
        m_isInstantiated = false;
        // invoke the destroy callback
        invoke(destroy);
        // destroy the service instance
        destroyService(state);
    }

    private void invoke(String name) {
        if (name != null) {
            // if a callback instance was specified, look for the method there, if not,
            // ask the service for its composition instances
            Object[] instances = m_callbackInstance != null ? new Object[] { m_callbackInstance } : getCompositionInstances();
            invokeCallbackMethod(instances, name,
                new Class[][] {{ Component.class }, {}},
                new Object[][] {{ this }, {}});
        }
    }

    public void invokeCallbackMethod(Object[] instances, String methodName, Class[][] signatures, Object[][] parameters) {
        for (int i = 0; i < instances.length; i++) {
            try {
                InvocationUtil.invokeCallbackMethod(instances[i], methodName, signatures, parameters);
            }
            catch (NoSuchMethodException e) {
                // if the method does not exist, ignore it
            }
            catch (InvocationTargetException e) {
                // the method itself threw an exception, log that
                m_logger.log(Logger.LOG_WARNING, "Invocation of '" + methodName + "' failed.", e.getCause());
            }
            catch (Exception e) {
                m_logger.log(Logger.LOG_WARNING, "Could not invoke '" + methodName + "'.", e);
            }
        }
    }

    private void startTrackingOptional(State state) {
        Iterator i = state.getDependencies().iterator();
        while (i.hasNext()) {
            Dependency dependency = (Dependency) i.next();
            if (!dependency.isRequired()) {
                ((DependencyActivation) dependency).start(this);
            }
        }
    }

    private void stopTrackingOptional(State state) {
        Iterator i = state.getDependencies().iterator();
        while (i.hasNext()) {
            Dependency dependency = (Dependency) i.next();
            if (!dependency.isRequired()) {
                ((DependencyActivation) dependency).stop(this);
            }
        }
    }

    private void startTrackingRequired(State state) {
        Iterator i = state.getDependencies().iterator();
        while (i.hasNext()) {
            Dependency dependency = (Dependency) i.next();
            if (dependency.isRequired()) {
                ((DependencyActivation) dependency).start(this);
            }
        }
    }

    private void stopTrackingRequired(State state) {
        Iterator i = state.getDependencies().iterator();
        while (i.hasNext()) {
            Dependency dependency = (Dependency) i.next();
            if (dependency.isRequired()) {
                ((DependencyActivation) dependency).stop(this);
            }
        }
    }

    private Object createInstance(Class clazz) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Constructor constructor = clazz.getConstructor(VOID);
		constructor.setAccessible(true);
        return constructor.newInstance(null);
    }

    public void initService() {
    	if (m_serviceInstance == null) {
	        if (m_implementation instanceof Class) {
	            // instantiate
	            try {
	            	m_serviceInstance = createInstance((Class) m_implementation);
	            }
	            catch (Exception e) {
	                m_logger.log(Logger.LOG_ERROR, "Could not create service instance of class " + m_implementation + ".", e);
				}
	        }
	        else {
	        	if (m_instanceFactoryCreateMethod != null) {
	        		Object factory = null;
		        	if (m_instanceFactory != null) {
		        		if (m_instanceFactory instanceof Class) {
		        			try {
								factory = createInstance((Class) m_instanceFactory);
							}
		                    catch (Exception e) {
		                        m_logger.log(Logger.LOG_ERROR, "Could not create factory instance of class " + m_instanceFactory + ".", e);
		                    }
		        		}
		        		else {
		        			factory = m_instanceFactory;
		        		}
		        	}
		        	else {
		        		// TODO review if we want to try to default to something if not specified
		        	    // for now the JavaDoc of setFactory(method) reflects the fact that we need
		        	    // to review it
		        	}
		        	if (factory == null) {
                        m_logger.log(Logger.LOG_ERROR, "Factory cannot be null.");
		        	}
		        	else {
    		        	try {
    						m_serviceInstance = InvocationUtil.invokeMethod(factory, factory.getClass(), m_instanceFactoryCreateMethod, new Class[][] {{}}, new Object[][] {{}}, false);
    					}
    		        	catch (Exception e) {
    	                    m_logger.log(Logger.LOG_ERROR, "Could not create service instance using factory " + factory + " method " + m_instanceFactoryCreateMethod + ".", e);
    					}
		        	}
	        	}
	        	if (m_serviceInstance == null) {
	        	    if (m_implementation == null) {
	        	        m_logger.log(Logger.LOG_ERROR, "Implementation cannot be null.");
	        	    }
	        	    m_serviceInstance = m_implementation;
	        	}
	        }
	        // configure the bundle context
	        if (((Boolean) m_autoConfig.get(BundleContext.class)).booleanValue()) {
	            configureImplementation(BundleContext.class, m_context, (String) m_autoConfigInstance.get(BundleContext.class));
	        }
            if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
                configureImplementation(ServiceRegistration.class, NULL_REGISTRATION, (String) m_autoConfigInstance.get(ServiceRegistration.class));
            }
            if (((Boolean) m_autoConfig.get(DependencyManager.class)).booleanValue()) {
                configureImplementation(DependencyManager.class, m_manager, (String) m_autoConfigInstance.get(DependencyManager.class));
            }
            if (((Boolean) m_autoConfig.get(Component.class)).booleanValue()) {
                configureImplementation(Component.class, this, (String) m_autoConfigInstance.get(Component.class));
            }
    	}
    }

    public synchronized Component setAutoConfig(Class clazz, boolean autoConfig) {
        m_autoConfig.put(clazz, Boolean.valueOf(autoConfig));
        return this;
    }

    public synchronized Component setAutoConfig(Class clazz, String instanceName) {
        m_autoConfig.put(clazz, Boolean.valueOf(instanceName != null));
        m_autoConfigInstance.put(clazz, instanceName);
        return this;
    }

    public boolean getAutoConfig(Class clazz) {
        Boolean result = (Boolean) m_autoConfig.get(clazz);
        return (result != null && result.booleanValue());
    }

    public String getAutoConfigInstance(Class clazz) {
        return (String) m_autoConfigInstance.get(clazz);
    }

    private void configureService(State state) {
        // configure all services (the optional dependencies might be configured
        // as null objects but that's what we want at this point)
        configureServices(state);
    }

    private void destroyService(State state) {
        unconfigureServices(state);
        m_serviceInstance = null;
    }

    private void registerService() {
        if (m_serviceName != null) {
            ServiceRegistrationImpl wrapper = new ServiceRegistrationImpl();
            m_registration = wrapper;
            if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
                configureImplementation(ServiceRegistration.class, m_registration, (String) m_autoConfigInstance.get(ServiceRegistration.class));
            }

            // service name can either be a string or an array of strings
            ServiceRegistration registration;

            // determine service properties
            Dictionary properties = calculateServiceProperties();

            // register the service
            try {
                if (m_serviceName instanceof String) {
                    registration = m_context.registerService((String) m_serviceName, m_serviceInstance, properties);
                }
                else {
                    registration = m_context.registerService((String[]) m_serviceName, m_serviceInstance, properties);
                }
                wrapper.setServiceRegistration(registration);
            }
            catch (IllegalArgumentException iae) {
                m_logger.log(Logger.LOG_ERROR, "Could not register service " + m_serviceInstance, iae);
                // set the registration to an illegal state object, which will make all invocations on this
                // wrapper fail with an ISE (which also occurs when the SR becomes invalid)
                wrapper.setIllegalState();
            }
        }
        m_isBound = true;
    }

	private Dictionary calculateServiceProperties() {
		Dictionary properties = new Properties();
		addTo(properties, m_serviceProperties);
		for (int i = 0; i < m_dependencies.size(); i++) {
			Dependency d = (Dependency) m_dependencies.get(i);
			if (d.isPropagated() && d.isAvailable()) {
				Dictionary dict = d.getProperties();
				addTo(properties, dict);
			}
		}
		if (properties.size() == 0) {
			properties = null;
		}
		return properties;
	}

	private void addTo(Dictionary properties, Dictionary additional) {
		if (properties == null) {
			throw new IllegalArgumentException("Dictionary to add to cannot be null.");
		}
		if (additional != null) {
			Enumeration e = additional.keys();
			while (e.hasMoreElements()) {
				Object key = e.nextElement();
				properties.put(key, additional.get(key));
			}
		}
	}

    private void unregisterService() {
        m_isBound = false;
        if (m_serviceName != null) {
            m_registration.unregister();
            configureImplementation(ServiceRegistration.class, NULL_REGISTRATION);
            m_registration = null;
        }
    }

    private void updateInstance(Dependency dependency) {
        if (dependency.isAutoConfig()) {
            configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
            if (dependency.isPropagated() && m_registration != null) {
                m_registration.setProperties(calculateServiceProperties());
            }
        }
    }

    /**
     * Configure a field in the service implementation. The service implementation
     * is searched for fields that have the same type as the class that was specified
     * and for each of these fields, the specified instance is filled in.
     *
     * @param clazz the class to search for
     * @param instance the instance to fill in
     * @param instanceName the name of the instance to fill in, or null if not used
     */
    private void configureImplementation(Class clazz, Object instance, String instanceName) {
    	Object[] instances = getCompositionInstances();
    	if (instances != null) {
	    	for (int i = 0; i < instances.length; i++) {
	    		Object serviceInstance = instances[i];
		        Class serviceClazz = serviceInstance.getClass();
		        if (Proxy.isProxyClass(serviceClazz)) {
		            serviceInstance = Proxy.getInvocationHandler(serviceInstance);
		            serviceClazz = serviceInstance.getClass();
		        }
		        while (serviceClazz != null) {
		            Field[] fields = serviceClazz.getDeclaredFields();
		            for (int j = 0; j < fields.length; j++) {
		                Field field = fields[j];
                        Class type = field.getType();
                        if ((instanceName == null && type.equals(clazz))
		                    || (instanceName != null && field.getName().equals(instanceName) && type.isAssignableFrom(clazz))) {
		                    try {
		                    	field.setAccessible(true);
		                        // synchronized makes sure the field is actually written to immediately
		                        synchronized (SYNC) {
		                            field.set(serviceInstance, instance);
		                        }
		                    }
		                    catch (Exception e) {
		                        m_logger.log(Logger.LOG_ERROR, "Could not set field " + field, e);
		                        return;
		                    }
		                }
		            }
		            serviceClazz = serviceClazz.getSuperclass();
		        }
	    	}
    	}
    }

    public Object[] getCompositionInstances() {
        Object[] instances = null;
        if (m_compositionManagerGetMethod != null) {
            if (m_compositionManager != null) {
                m_compositionManagerInstance = m_compositionManager;
            }
            else {
                m_compositionManagerInstance = m_serviceInstance;
            }
            if (m_compositionManagerInstance != null) {
                try {
                    instances = (Object[]) InvocationUtil.invokeMethod(m_compositionManagerInstance, m_compositionManagerInstance.getClass(), m_compositionManagerGetMethod, new Class[][] {{}}, new Object[][] {{}}, false);
                }
                catch (Exception e) {
                    m_logger.log(Logger.LOG_ERROR, "Could not obtain instances from the composition manager.", e);
                    instances = m_serviceInstance == null ? new Object[] {} : new Object[] { m_serviceInstance };
                }
            }
        }
        else {
            instances = m_serviceInstance == null ? new Object[] {} : new Object[] { m_serviceInstance };
        }
        return instances;
    }

    private void configureImplementation(Class clazz, Object instance) {
        configureImplementation(clazz, instance, null);
    }

    private void configureServices(State state) {
        Iterator i = state.getDependencies().iterator();
        while (i.hasNext()) {
            Dependency dependency = (Dependency) i.next();
            if (dependency.isAutoConfig()) {
                configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
            }
            if (dependency.isRequired()) {
                dependency.invokeAdded(this);
            }
        }
    }

    private void unconfigureServices(State state) {
        Iterator i = state.getDependencies().iterator();
        while (i.hasNext()) {
            Dependency dependency = (Dependency) i.next();
            if (dependency.isRequired()) {
                dependency.invokeRemoved(this);
            }
        }
    }

    protected void ensureNotActive() {
    	State state;
    	synchronized (m_dependencies) {
    		state = m_state;
    	}
    	if (!state.isInactive()) {
            throw new IllegalStateException("Cannot modify state while active.");
        }
    }

    public boolean isRegistered() {
    	State state;
    	synchronized (m_dependencies) {
    		state = m_state;
    	}
        return (state.isAllRequiredAvailable());
    }

    public boolean isInstantiated() {
        State state;
        synchronized (m_dependencies) {
            state = m_state;
        }
        return (state.isTrackingOptional() || state.isBound() || state.isWaitingForRequiredInstantiated());
    }

    // ServiceComponent interface

    static class SCDImpl implements ComponentDependencyDeclaration {
        private final String m_name;
        private final int m_state;
        private final String m_type;

        public SCDImpl(String name, int state, String type) {
            m_name = name;
            m_state = state;
            m_type = type;
        }

        public String getName() {
            return m_name;
        }

        public int getState() {
            return m_state;
        }

        public String getType() {
            return m_type;
        }
    }

    public ComponentDependencyDeclaration[] getComponentDependencies() {
        List deps = getDependencies();
        if (deps != null) {
            ComponentDependencyDeclaration[] result = new ComponentDependencyDeclaration[deps.size()];
            for (int i = 0; i < result.length; i++) {
                Dependency dep = (Dependency) deps.get(i);
                if (dep instanceof ComponentDependencyDeclaration) {
                    result[i] = (ComponentDependencyDeclaration) dep;
                }
                else {
                    result[i] = new SCDImpl(dep.toString(), (dep.isAvailable() ? 1 : 0) + (dep.isRequired() ? 2 : 0), dep.getClass().getName());
                }
            }
            return result;
        }
        return null;
    }

    public String getName() {
        Object serviceName = m_serviceName;
        if (serviceName instanceof String[]) {
            StringBuffer sb = new StringBuffer();
            String[] names = (String[]) serviceName;
            for (int i = 0; i < names.length; i++) {
                if (i > 0) {
                    sb.append(", ");
                }
                sb.append(names[i]);
            }
            sb.append('(');
            sb.append(propertiesToString());
            sb.append(')');
            return sb.toString();
        }
        else if (serviceName instanceof String) {
            return serviceName.toString() + "(" + propertiesToString() + ")";
        }
        else {
            Object implementation = m_implementation;
            if (implementation != null) {
                return implementation.toString();
            }
            else {
                return super.toString();
            }
        }
    }

    private String propertiesToString() {
        StringBuffer result = new StringBuffer();
        Dictionary properties = calculateServiceProperties();
        if (properties != null) {
            Enumeration enumeration = properties.keys();
            while (enumeration.hasMoreElements()) {
                Object key = enumeration.nextElement();
                if (result.length() > 0) {
                    result.append(',');
                }
                result.append(key.toString());
                result.append('=');
                Object value = properties.get(key);
                if (value instanceof String[]) {
                    String[] values = (String[]) value;
                    result.append('{');
                    for (int i = 0; i < values.length; i++) {
                        if (i > 0) {
                            result.append(',');
                        }
                        result.append(values[i].toString());
                    }
                    result.append('}');
                }
                else {
                    result.append(value.toString());
                }
            }
        }
        return result.toString();
    }

    public int getState() {
        return (isRegistered() ? 1 : 0);
    }

    public DependencyManager getDependencyManager() {
        return m_manager;
    }

    static {
        NULL_REGISTRATION = (ServiceRegistration) Proxy.newProxyInstance(ComponentImpl.class.getClassLoader(), new Class[] {ServiceRegistration.class}, new DefaultNullObject());
    }

    public BundleContext getBundleContext() {
        return m_context;
    }

    public int compareTo(Object object) {
        if (object instanceof ComponentImpl) {
            ComponentImpl other = (ComponentImpl) object;
            long id1 = this.getBundleContext().getBundle().getBundleId();
            long id2 = ((ComponentImpl) other).getBundleContext().getBundle().getBundleId();
            if (id1 == id2) {
                return (int)(this.m_id - other.m_id);
            }
            return (int)(id1 - id2);
        }
        return -1;
    }
}


text:
<?php

use Mockery as m;
use Illuminate\View\Factory;

class ViewFactoryTest extends PHPUnit_Framework_TestCase
{
    public function tearDown()
    {
        m::close();
    }

    public function testMakeCreatesNewViewInstanceWithProperPathAndEngine()
    {
        unset($_SERVER['__test.view']);

        $factory = $this->getFactory();
        $factory->getFinder()->shouldReceive('find')->once()->with('view')->andReturn('path.php');
        $factory->getEngineResolver()->shouldReceive('resolve')->once()->with('php')->andReturn($engine = m::mock('Illuminate\View\Engines\EngineInterface'));
        $factory->getFinder()->shouldReceive('addExtension')->once()->with('php');
        $factory->setDispatcher(new Illuminate\Events\Dispatcher);
        $factory->creator('view', function ($view) {
            $_SERVER['__test.view'] = $view;
        });
        $factory->addExtension('php', 'php');
        $view = $factory->make('view', ['foo' => 'bar'], ['baz' => 'boom']);

        $this->assertSame($engine, $view->getEngine());
        $this->assertSame($_SERVER['__test.view'], $view);

        unset($_SERVER['__test.view']);
    }

    public function testExistsPassesAndFailsViews()
    {
        $factory = $this->getFactory();
        $factory->getFinder()->shouldReceive('find')->once()->with('foo')->andThrow('InvalidArgumentException');
        $factory->getFinder()->shouldReceive('find')->once()->with('bar')->andReturn('path.php');

        $this->assertFalse($factory->exists('foo'));
        $this->assertTrue($factory->exists('bar'));
    }

    public function testRenderEachCreatesViewForEachItemInArray()
    {
        $factory = m::mock('Illuminate\View\Factory[make]', $this->getFactoryArgs());
        $factory->shouldReceive('make')->once()->with('foo', ['key' => 'bar', 'value' => 'baz'])->andReturn($mockView1 = m::mock('StdClass'));
        $factory->shouldReceive('make')->once()->with('foo', ['key' => 'breeze', 'value' => 'boom'])->andReturn($mockView2 = m::mock('StdClass'));
        $mockView1->shouldReceive('render')->once()->andReturn('dayle');
        $mockView2->shouldReceive('render')->once()->andReturn('rees');

        $result = $factory->renderEach('foo', ['bar' => 'baz', 'breeze' => 'boom'], 'value');

        $this->assertEquals('daylerees', $result);
    }

    public function testEmptyViewsCanBeReturnedFromRenderEach()
    {
        $factory = m::mock('Illuminate\View\Factory[make]', $this->getFactoryArgs());
        $factory->shouldReceive('make')->once()->with('foo')->andReturn($mockView = m::mock('StdClass'));
        $mockView->shouldReceive('render')->once()->andReturn('empty');

        $this->assertEquals('empty', $factory->renderEach('view', [], 'iterator', 'foo'));
    }

    public function testAddANamedViews()
    {
        $factory = $this->getFactory();
        $factory->name('bar', 'foo');

        $this->assertEquals(['foo' => 'bar'], $factory->getNames());
    }

    public function testMakeAViewFromNamedView()
    {
        $factory = $this->getFactory();
        $factory->getFinder()->shouldReceive('find')->once()->with('view')->andReturn('path.php');
        $factory->getEngineResolver()->shouldReceive('resolve')->once()->with('php')->andReturn($engine = m::mock('Illuminate\View\Engines\EngineInterface'));
        $factory->getFinder()->shouldReceive('addExtension')->once()->with('php');
        $factory->getDispatcher()->shouldReceive('fire');
        $factory->addExtension('php', 'php');
        $factory->name('view', 'foo');
        $view = $factory->of('foo', ['data']);

        $this->assertSame($engine, $view->getEngine());
    }

    public function testRawStringsMayBeReturnedFromRenderEach()
    {
        $this->assertEquals('foo', $this->getFactory()->renderEach('foo', [], 'item', 'raw|foo'));
    }

    public function testEnvironmentAddsExtensionWithCustomResolver()
    {
        $factory = $this->getFactory();

        $resolver = function () {
        };

        $factory->getFinder()->shouldReceive('addExtension')->once()->with('foo');
        $factory->getEngineResolver()->shouldReceive('register')->once()->with('bar', $resolver);
        $factory->getFinder()->shouldReceive('find')->once()->with('view')->andReturn('path.foo');
        $factory->getEngineResolver()->shouldReceive('resolve')->once()->with('bar')->andReturn($engine = m::mock('Illuminate\View\Engines\EngineInterface'));
        $factory->getDispatcher()->shouldReceive('fire');

        $factory->addExtension('foo', 'bar', $resolver);

        $view = $factory->make('view', ['data']);
        $this->assertSame($engine, $view->getEngine());
    }

    public function testAddingExtensionPrependsNotAppends()
    {
        $factory = $this->getFactory();
        $factory->getFinder()->shouldReceive('addExtension')->once()->with('foo');

        $factory->addExtension('foo', 'bar');

        $extensions = $factory->getExtensions();
        $this->assertEquals('bar', reset($extensions));
        $this->assertEquals('foo', key($extensions));
    }

    public function testPrependedExtensionOverridesExistingExtensions()
    {
        $factory = $this->getFactory();
        $factory->getFinder()->shouldReceive('addExtension')->once()->with('foo');
        $factory->getFinder()->shouldReceive('addExtension')->once()->with('baz');

        $factory->addExtension('foo', 'bar');
        $factory->addExtension('baz', 'bar');

        $extensions = $factory->getExtensions();
        $this->assertEquals('bar', reset($extensions));
        $this->assertEquals('baz', key($extensions));
    }

    public function testComposersAreProperlyRegistered()
    {
        $factory = $this->getFactory();
        $factory->getDispatcher()->shouldReceive('listen')->once()->with('composing: foo', m::type('Closure'));
        $callback = $factory->composer('foo', function () {
            return 'bar';
        });
        $callback = $callback[0];

        $this->assertEquals('bar', $callback());
    }

    public function testComposersAreProperlyRegisteredWithPriority()
    {
        $factory = $this->getFactory();
        $factory->getDispatcher()->shouldReceive('listen')->once()->with('composing: foo', m::type('Closure'), 1);
        $callback = $factory->composer('foo', function () {
            return 'bar';
        }, 1);
        $callback = $callback[0];

        $this->assertEquals('bar', $callback());
    }

    public function testComposersCanBeMassRegistered()
    {
        $factory = $this->getFactory();
        $factory->getDispatcher()->shouldReceive('listen')->once()->with('composing: bar', m::type('Closure'));
        $factory->getDispatcher()->shouldReceive('listen')->once()->with('composing: qux', m::type('Closure'));
        $factory->getDispatcher()->shouldReceive('listen')->once()->with('composing: foo', m::type('Closure'));
        $composers = $factory->composers([
            'foo' => 'bar',
            'baz@baz' => ['qux', 'foo'],
        ]);

        $this->assertCount(3, $composers);
        $reflections = [
            new ReflectionFunction($composers[0]),
            new ReflectionFunction($composers[1]),
        ];
        $this->assertEquals(['class' => 'foo', 'method' => 'compose'], $reflections[0]->getStaticVariables());
        $this->assertEquals(['class' => 'baz', 'method' => 'baz'], $reflections[1]->getStaticVariables());
    }

    public function testClassCallbacks()
    {
        $factory = $this->getFactory();
        $factory->getDispatcher()->shouldReceive('listen')->once()->with('composing: foo', m::type('Closure'));
        $factory->setContainer($container = m::mock('Illuminate\Container\Container'));
        $container->shouldReceive('make')->once()->with('FooComposer')->andReturn($composer = m::mock('StdClass'));
        $composer->shouldReceive('compose')->once()->with('view')->andReturn('composed');
        $callback = $factory->composer('foo', 'FooComposer');
        $callback = $callback[0];

        $this->assertEquals('composed', $callback('view'));
    }

    public function testClassCallbacksWithMethods()
    {
        $factory = $this->getFactory();
        $factory->getDispatcher()->shouldReceive('listen')->once()->with('composing: foo', m::type('Closure'));
        $factory->setContainer($container = m::mock('Illuminate\Container\Container'));
        $container->shouldReceive('make')->once()->with('FooComposer')->andReturn($composer = m::mock('StdClass'));
        $composer->shouldReceive('doComposer')->once()->with('view')->andReturn('composed');
        $callback = $factory->composer('foo', 'FooComposer@doComposer');
        $callback = $callback[0];

        $this->assertEquals('composed', $callback('view'));
    }

    public function testCallComposerCallsProperEvent()
    {
        $factory = $this->getFactory();
        $view = m::mock('Illuminate\View\View');
        $view->shouldReceive('getName')->once()->andReturn('name');
        $factory->getDispatcher()->shouldReceive('fire')->once()->with('composing: name', [$view]);

        $factory->callComposer($view);
    }

    public function testComposersAreRegisteredWithSlashAndDot()
    {
        $factory = $this->getFactory();
        $factory->getDispatcher()->shouldReceive('listen')->with('composing: foo.bar', m::any())->twice();
        $factory->composer('foo.bar', '');
        $factory->composer('foo/bar', '');
    }

    public function testRenderCountHandling()
    {
        $factory = $this->getFactory();
        $factory->incrementRender();
        $this->assertFalse($factory->doneRendering());
        $factory->decrementRender();
        $this->assertTrue($factory->doneRendering());
    }

    public function testBasicSectionHandling()
    {
        $factory = $this->getFactory();
        $factory->startSection('foo');
        echo 'hi';
        $factory->stopSection();
        $this->assertEquals('hi', $factory->yieldContent('foo'));
    }

    public function testSectionExtending()
    {
        $placeholder = Illuminate\View\Factory::parentPlaceholder();
        $factory = $this->getFactory();
        $factory->startSection('foo');
        echo 'hi '.$placeholder;
        $factory->stopSection();
        $factory->startSection('foo');
        echo 'there';
        $factory->stopSection();
        $this->assertEquals('hi there', $factory->yieldContent('foo'));
    }

    public function testSectionMultipleExtending()
    {
        $placeholder = Illuminate\View\Factory::parentPlaceholder();
        $factory = $this->getFactory();
        $factory->startSection('foo');
        echo 'hello '.$placeholder.' nice to see you '.$placeholder;
        $factory->stopSection();
        $factory->startSection('foo');
        echo 'my '.$placeholder;
        $factory->stopSection();
        $factory->startSection('foo');
        echo 'friend';
        $factory->stopSection();
        $this->assertEquals('hello my friend nice to see you my friend', $factory->yieldContent('foo'));
    }

    public function testSingleStackPush()
    {
        $factory = $this->getFactory();
        $factory->startPush('foo');
        echo 'hi';
        $factory->stopPush();
        $this->assertEquals('hi', $factory->yieldPushContent('foo'));
    }

    public function testMultipleStackPush()
    {
        $factory = $this->getFactory();
        $factory->startPush('foo');
        echo 'hi';
        $factory->stopPush();
        $factory->startPush('foo');
        echo ', Hello!';
        $factory->stopPush();
        $this->assertEquals('hi, Hello!', $factory->yieldPushContent('foo'));

        // mimic a parent view is rendering
        $factory->incrementRender();
        $factory->startPush('foo');
        echo 'Dear ';
        $factory->stopPush();
        $factory->startPush('foo');
        echo 'friend';
        $factory->stopPush();
        $factory->decrementRender();

        $this->assertEquals('Dear friendhi, Hello!', $factory->yieldPushContent('foo'));
    }

    public function testSessionAppending()
    {
        $factory = $this->getFactory();
        $factory->startSection('foo');
        echo 'hi';
        $factory->appendSection();
        $factory->startSection('foo');
        echo 'there';
        $factory->appendSection();
        $this->assertEquals('hithere', $factory->yieldContent('foo'));
    }

    public function testYieldSectionStopsAndYields()
    {
        $factory = $this->getFactory();
        $factory->startSection('foo');
        echo 'hi';
        $this->assertEquals('hi', $factory->yieldSection());
    }

    public function testInjectStartsSectionWithContent()
    {
        $factory = $this->getFactory();
        $factory->inject('foo', 'hi');
        $this->assertEquals('hi', $factory->yieldContent('foo'));
    }

    public function testEmptyStringIsReturnedForNonSections()
    {
        $factory = $this->getFactory();
        $this->assertEmpty($factory->yieldContent('foo'));
    }

    public function testSectionFlushing()
    {
        $factory = $this->getFactory();
        $factory->startSection('foo');
        echo 'hi';
        $factory->stopSection();

        $this->assertCount(1, $factory->getSections());

        $factory->flushSections();

        $this->assertCount(0, $factory->getSections());
    }

    public function testHasSection()
    {
        $factory = $this->getFactory();
        $factory->startSection('foo');
        echo 'hi';
        $factory->stopSection();

        $this->assertTrue($factory->hasSection('foo'));
        $this->assertFalse($factory->hasSection('bar'));
    }

    public function testMakeWithSlashAndDot()
    {
        $factory = $this->getFactory();
        $factory->getFinder()->shouldReceive('find')->twice()->with('foo.bar')->andReturn('path.php');
        $factory->getEngineResolver()->shouldReceive('resolve')->twice()->with('php')->andReturn(m::mock('Illuminate\View\Engines\EngineInterface'));
        $factory->getDispatcher()->shouldReceive('fire');
        $factory->make('foo/bar');
        $factory->make('foo.bar');
    }

    public function testNamespacedViewNamesAreNormalizedProperly()
    {
        $factory = $this->getFactory();
        $factory->getFinder()->shouldReceive('find')->twice()->with('vendor/package::foo.bar')->andReturn('path.php');
        $factory->getEngineResolver()->shouldReceive('resolve')->twice()->with('php')->andReturn(m::mock('Illuminate\View\Engines\EngineInterface'));
        $factory->getDispatcher()->shouldReceive('fire');
        $factory->make('vendor/package::foo/bar');
        $factory->make('vendor/package::foo.bar');
    }

    public function testMakeWithAlias()
    {
        $factory = $this->getFactory();
        $factory->alias('real', 'alias');
        $factory->getFinder()->shouldReceive('find')->once()->with('real')->andReturn('path.php');
        $factory->getEngineResolver()->shouldReceive('resolve')->once()->with('php')->andReturn(m::mock('Illuminate\View\Engines\EngineInterface'));
        $factory->getDispatcher()->shouldReceive('fire');

        $view = $factory->make('alias');

        $this->assertEquals('real', $view->getName());
    }

    /**
     * @expectedException InvalidArgumentException
     */
    public function testExceptionIsThrownForUnknownExtension()
    {
        $factory = $this->getFactory();
        $factory->getFinder()->shouldReceive('find')->once()->with('view')->andReturn('view.foo');
        $factory->make('view');
    }

    /**
     * @expectedException Exception
     * @expectedExceptionMessage section exception message
     */
    public function testExceptionsInSectionsAreThrown()
    {
        $engine = new Illuminate\View\Engines\CompilerEngine(m::mock('Illuminate\View\Compilers\CompilerInterface'));
        $engine->getCompiler()->shouldReceive('getCompiledPath')->andReturnUsing(function ($path) {
            return $path;
        });
        $engine->getCompiler()->shouldReceive('isExpired')->twice()->andReturn(false);
        $factory = $this->getFactory();
        $factory->getEngineResolver()->shouldReceive('resolve')->twice()->andReturn($engine);
        $factory->getFinder()->shouldReceive('find')->once()->with('layout')->andReturn(__DIR__.'/fixtures/section-exception-layout.php');
        $factory->getFinder()->shouldReceive('find')->once()->with('view')->andReturn(__DIR__.'/fixtures/section-exception.php');
        $factory->getDispatcher()->shouldReceive('fire')->times(4);

        $factory->make('view')->render();
    }

    /**
     * @expectedException InvalidArgumentException
     * @expectedExceptionMessage Cannot end a section without first starting one.
     */
    public function testExtraStopSectionCallThrowsException()
    {
        $factory = $this->getFactory();
        $factory->startSection('foo');
        $factory->stopSection();

        $factory->stopSection();
    }

    /**
     * @expectedException InvalidArgumentException
     * @expectedExceptionMessage Cannot end a section without first starting one.
     */
    public function testExtraAppendSectionCallThrowsException()
    {
        $factory = $this->getFactory();
        $factory->startSection('foo');
        $factory->stopSection();

        $factory->appendSection();
    }

    public function testAddingLoops()
    {
        $factory = $this->getFactory();

        $factory->addLoop([1, 2, 3]);

        $expectedLoop = [
            'iteration' => 0,
            'index' => 0,
            'remaining' => 3,
            'count' => 3,
            'first' => true,
            'last' => false,
            'depth' => 1,
            'parent' => null,
        ];

        $this->assertEquals([$expectedLoop], $factory->getLoopStack());

        $factory->addLoop([1, 2, 3, 4]);

        $secondExpectedLoop = [
            'iteration' => 0,
            'index' => 0,
            'remaining' => 4,
            'count' => 4,
            'first' => true,
            'last' => false,
            'depth' => 2,
            'parent' => (object) $expectedLoop,
        ];
        $this->assertEquals([$expectedLoop, $secondExpectedLoop], $factory->getLoopStack());

        $factory->popLoop();

        $this->assertEquals([$expectedLoop], $factory->getLoopStack());
    }

    public function testAddingUncountableLoop()
    {
        $factory = $this->getFactory();

        $factory->addLoop('');

        $expectedLoop = [
            'iteration' => 0,
            'index' => 0,
            'remaining' => null,
            'count' => null,
            'first' => true,
            'last' => null,
            'depth' => 1,
            'parent' => null,
        ];

        $this->assertEquals([$expectedLoop], $factory->getLoopStack());
    }

    public function testIncrementingLoopIndices()
    {
        $factory = $this->getFactory();

        $factory->addLoop([1, 2, 3, 4]);

        $factory->incrementLoopIndices();

        $factory->incrementLoopIndices();

        $this->assertEquals(2, $factory->getLoopStack()[0]['iteration']);
        $this->assertEquals(1, $factory->getLoopStack()[0]['index']);
        $this->assertEquals(2, $factory->getLoopStack()[0]['remaining']);
    }

    public function testReachingEndOfLoop()
    {
        $factory = $this->getFactory();

        $factory->addLoop([1, 2]);

        $factory->incrementLoopIndices();

        $factory->incrementLoopIndices();

        $this->assertTrue($factory->getLoopStack()[0]['last']);
    }

    public function testIncrementingLoopIndicesOfUncountable()
    {
        $factory = $this->getFactory();

        $factory->addLoop('');

        $factory->incrementLoopIndices();

        $factory->incrementLoopIndices();

        $this->assertEquals(2, $factory->getLoopStack()[0]['iteration']);
        $this->assertEquals(1, $factory->getLoopStack()[0]['index']);
        $this->assertFalse($factory->getLoopStack()[0]['first']);
        $this->assertNull($factory->getLoopStack()[0]['remaining']);
        $this->assertNull($factory->getLoopStack()[0]['last']);
    }

    protected function getFactory()
    {
        return new Factory(
            m::mock('Illuminate\View\Engines\EngineResolver'),
            m::mock('Illuminate\View\ViewFinderInterface'),
            m::mock('Illuminate\Contracts\Events\Dispatcher')
        );
    }

    protected function getFactoryArgs()
    {
        return [
            m::mock('Illuminate\View\Engines\EngineResolver'),
            m::mock('Illuminate\View\ViewFinderInterface'),
            m::mock('Illuminate\Contracts\Events\Dispatcher'),
        ];
    }
}