diff --git a/vendor/libv8-convert/cvv8/ClassCreator.hpp b/vendor/libv8-convert/cvv8/ClassCreator.hpp deleted file mode 100644 index 4a8b6d7d9..000000000 --- a/vendor/libv8-convert/cvv8/ClassCreator.hpp +++ /dev/null @@ -1,1286 +0,0 @@ -#if !defined(CODE_GOOGLE_COM_P_V8_CONVERT_CLASS_CREATOR_HPP_INCLUDED) -#define CODE_GOOGLE_COM_P_V8_CONVERT_CLASS_CREATOR_HPP_INCLUDED 1 -/** LICENSE - - This software's source code, including accompanying documentation and - demonstration applications, are licensed under the following - conditions... - - The author (Stephan G. Beal [http://wanderinghorse.net/home/stephan/]) - explicitly disclaims copyright in all jurisdictions which recognize - such a disclaimer. In such jurisdictions, this software is released - into the Public Domain. - - In jurisdictions which do not recognize Public Domain property - (e.g. Germany as of 2011), this software is Copyright (c) 2011 - by Stephan G. Beal, and is released under the terms of the MIT License - (see below). - - In jurisdictions which recognize Public Domain property, the user of - this software may choose to accept it either as 1) Public Domain, 2) - under the conditions of the MIT License (see below), or 3) under the - terms of dual Public Domain/MIT License conditions described here, as - they choose. - - The MIT License is about as close to Public Domain as a license can - get, and is described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - - The full text of the MIT License follows: - - -- - Copyright (c) 2011 Stephan G. Beal (http://wanderinghorse.net/home/stephan/) - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - --END OF MIT LICENSE-- - - For purposes of the above license, the term "Software" includes - documentation and demonstration source code which accompanies - this software. ("Accompanies" = is contained in the Software's - primary public source code repository.) - -*/ - -#include -#include -#include "convert.hpp" -//#include // only for debuggering -#include "NativeToJSMap.hpp" -namespace cvv8 { - - /** - Policy template used by ClassCreator for - instantiating T objects. - */ - template - class ClassCreator_Factory - { - public: - typedef T * ReturnType; - /** - Must instantiate a new T object based on the given - arguments. On error it should throw an exception (which the - binding framework will convert to a JS-side exception). It - may also return NULL on error, but the error message - probably won't be as clear for the user. - - Ownership of the object is passed to the caller (the - binding API internals), and eventually given to v8. - - jsSelf will be the newly-created JS-side 'this' object. It - is not normally required by this function but it is - sometimes useful when we need to bind supplementary - properties in the ctor, especially when binding a "pure - C++" class which has no native place to store such - properties. - - At the time this is called, jsSelf is not connected to the - native (because it hasn't yet been created). - Implementations must not perform the actual binding of the - returned native to jsSelf - ClassCreator will do that - immediately after Create() returns the new object. - - The default implementation simply return (new T). - */ - static ReturnType Create( v8::Persistent & jsSelf, v8::Arguments const & argv ) - { - return new T; - } - - /** - Must destroy obj using a mechanism complementary to its - construction via a prior call to Create(). - - The default implementation simply calls (delete obj). - */ - static void Delete( T * obj ) - { - delete obj; - } - }; - - /** - Base class for static ClassCreator options. - */ - template - struct Opt_ConstVal - { - typedef ValT Type; - const static Type Value = Val; - }; - - /** - Base class for static integer ClassCreator options. - */ - template - struct Opt_Int : Opt_ConstVal - {}; - - /** - Base class for static boolean ClassCreator options. - */ - template - struct Opt_Bool : Opt_ConstVal - {}; - - /** - A ClassCreator policy/option class responsible specifying whether - or not a ClassCreator-bound class should allow "Foo()" and "new - Foo()" to behave the same or not. If the Value member is false - (the default) then "Foo()" is not allowed to behave as a - constructor call (it will generate an error), otherwise it will - be treated exactly as if "new Foo()" had been called. - */ - template - struct ClassCreator_AllowCtorWithoutNew : Opt_Bool - {}; - - /** - ClassCreator policy which determines whether lookups for native - types in JS objects should walk through the prototype - chain. This can decrease the speed of JS-to-this operations and - is necessary only if bound types will be subclassed (either from - other bound native types or from JS classes). - - The default value is true for the sake of usability. If JS-side - subclassing will never be used, you can potentially optimize out a - few lookup operations by creating the specialization by subclassing - Opt_Bool. - */ - template - struct ClassCreator_SearchPrototypeForThis : Opt_Bool - {}; - - /** - ClassCreator policy type which defines a "type ID" value - for a type wrapped using ClassCreator. This is used - together with JSToNative_ObjectWithInternalFieldsTypeSafe - (type THAT 10 times fast) to provide a lightweight - (but highly effective) type check when extracting - natives from v8 (as void pointers). The default - implementation is fine for all cases i can think of, but i can - concieve of one or two uses for specializations (e.g. storing the - JS-side name of the class as the type ID). - - The type id must be unique per type except that subtypes may - (depending on various other binding options) may need use the same - value as the parent type. If multiple types share the same type ID, - the type-safety check can be bypassed, _potentially_ leading to an - illegal static_cast() and subsequent mis-use of the pointer. i - stress the word "potentially" because to get that condition one - would have to (A) abuse the object via the C++ API (which doesn't - happen via the binding process, and you're probably also not going - to do it) or (B) write some script code to confuse two bound native - types about who is really who when a particular member is called. - - In the case of subclassed bound types, the - ClassCreator_TypeID impl should subclass - ClassCreator_TypeID. Whether or not this is _required_ - for proper functionality depends at least in part on whether - (ClassCreator_InternalFields::TypeIDIndex>=0). If it is - negative, subclasses do not need to explicitly define this policy - because the type ID won't be used for purposes of validating a JS-held - pointer's native type. - - TODO: see if we can consolidate this type with TypeName<>. The problem - at the moment is that JSToNative_ObjectWithInternalFieldsTypeSafe - takes a (void const * &) and TypeName::Value is a (char const *), which - won't convert to (void const *) in the context of template parameters. - */ - template - struct ClassCreator_TypeID - { - const static void * Value; - }; - template - const void * ClassCreator_TypeID::Value = TypeName::Value; - - /** - Convenience base type for ClassCreator_InternalFields - implementations. - - See the member documentation for the meaning of - HowMany and Index. - - If any of the following conditions are met then - a compile-time assertion is triggered: - - - (ObjectIndex<0) - - - (ObjectIndex>=HowMany) - - - (TypeIndex>=HowMany). - - - (TypeIndex == ObjectIndex) - - TypeIndex may be negative, which indicates to ClassCreator that the - binding should not store type ID information. However, if it is - negative then T must not be used together with - JSToNative_ObjectWithInternalFieldsTypeSafe - doing so will trigger - a compile-time assertion. - */ - template - struct ClassCreator_InternalFields_Base - { - /** - Total number of internal fields assigned to JS-side T - objects. - */ - static const int Count = HowMany; - - /** - The internal field index at which ClassCreator policies should - expect the native object to be found in any given JS object. - It must be 0 or greater, and must be less than Value. - */ - static const int NativeIndex = ObjectIndex; - - /** - The internal field index at which ClassCreator policies - should expect a type identifier tag to be stored. - This can be used in conjunction with - JSToNative_ObjectWithInternalFieldsTypeSafe (or similar) - to provide an extra level of type safety at JS runtime. - - */ - static const int TypeIDIndex = TypeIndex; - private: - typedef char AssertFields[ - (HowMany > TypeIndex) - && (HowMany > ObjectIndex) - && (TypeIndex != ObjectIndex) - && (ObjectIndex >= 0) - ? 1 : -1]; - }; - - /** - The ClassCreator policy which sets the number of internal - fields reserved for JS objects and the internal field index - (0-based) at which the native object is stored . The Count - value must be greater than 0 and greater than the NativeIndex - member. Failing to meet these prerequisites will cause a - compile-time assertion to be triggered. - - ACHTUNG SUBCLASSERS: - - When using a heirarchy of native types, more than one of which - is compatible with CastFromJS(), conversions from subtype to - base type will fail unless all subtypes use the same internal - field placement as the parent type. If this code can detect a - mismatch then it will fail gracefully (e.g. a JS-side - exception), and if not then it might mis-cast an object and - cause Undefined Behaviour. - - If a given parent type uses a custom ClassCreator_InternalFields - specialization then to ensure that subclasses always have the - same placement, they "should" define their own policy like - this: - - @code - template <> - struct ClassCreator_InternalFields< SubType > - : ClassCreator_InternalFields< ParentType > - {}; - @endcode - - That prohibits special internal field handling in the subtypes, - but experience hasn't shown that subclasses need their own - internal fields. Normaly a single internal field is all we need - when binding native data. And when i say "normally", i mean - "almost always." - - This must-match requirement is partially a side-effect of the library - internally using the field count as a santiy check before trying to - extract data from internal fields. It also exists so that the - optional (but recommended) type-safety-check support (added in late - June 2011: see JSToNative_ObjectWithInternalFieldsTypeSafe) will - treat the subclasses as instances of the base class. - */ - template - struct ClassCreator_InternalFields : ClassCreator_InternalFields_Base - { - }; - - - /** - This policy is used by ClassCreator::SetupBindings() as the generic - interface for plugging in a bound class. Clients are not required to - specialise this, but see this class' Initialize() for what might - happen if they don't. - */ - template - struct ClassCreator_SetupBindings - { - /** - Specializations should perform any class/function-related binding - here, adding their functionality to the given object (which is - normally the logical global object but need not be). (Note that the - handle refererence is const but that object itself can be modified. - - The default implementation throws an exception deriving from - std::exception, so it must be specialized to be useful. A default - specialization exists because there are probably a few cases - out there which don't really need this. But most (if not all) - need a setup function, and this is the official one for - ClassCreator-wrapped types. Implementations may of course simply - forward the call to another, client-provided function. - - On error the binding should throw a NATIVE exception (ideally - deriving from std::exception because (A) it's portable practice - and (B) parts of the cvv8 API handles those explicitly). - - Several years of experience have shown that this function (or - similar implementations) should take some care to make sure - not to set up their bindings twice. We can do that by using the - following pattern: - - @code - typedef ClassCreator CC; - CC & cc( CC::Instance() ); - if( cc.IsSealed() ) { - cc.AddClassTo( "T", dest ); - return; - } - - // ... do your bindings here... - - // As the final step: - cc.AddClassTo( "T", dest ); - return; - @endcode - - If you do not actually want to add the class to the dest object, - you should call Seal() instead of AddClassTo() (or pass a different - destination object to AddClassTo(). - */ - static void Initialize( v8::Handle const & target ) - { - throw std::runtime_error("ClassCreator_SetupBindings MUST be specialized " - "in order to be useful!"); - } - }; - - /** - A concrete ClassCreator_SetupBindings implementation which forwards - the call to a user-defined function. - */ - template const &) > - struct ClassCreator_SetupBindings_ClientFunc - { - /** - Calls Func(target). - */ - static void Initialize( v8::Handle const & target ) - { - Func(target); - } - }; - - /** - The ClassCreator policy class responsible for doing optional - class-specific binding-related work as part of the JS/Native - object construction process. - - The default specialization does nothing (which is okay for the - general case) but defines the interface which specializations - must implement. - - Reminder to self: we could arguably benefit by splitting this policy - into 3 classes, but experience has shown that the metadata used by - the 3 functions are typically shared amongst the 3 implementations - (or 2 of them in most cases). - */ - template - struct ClassCreator_WeakWrap - { - typedef typename TypeInfo::NativeHandle NativeHandle; - - /** - Similar to Wrap(), but this is called before the native constructor is called. - It is rarely needed, but is necessary if one needs to manipulate the JS - "this" object before the native object is constructed, so that the native ctor - can access information stored in the JS-side internal fields. - - If this throws a native exception, construction of the - object will fail and Unwrap() is called, passed - (jsSelf,NULL), to clean up any data which this function might have - stored in jsSelf. - - The argv object is the arguments passed to the constructor. - - The default implementation does nothing. - */ - static void PreWrap( v8::Persistent const &, v8::Arguments const & ) - { - return; - } - - - /** - This operation is called one time from ClassCreator for each - new object, directly after the native has been connected to - a Persistent handle. - - Note that the ClassCreator code which calls this has already - taken care of connecting nativeSelf to jsSelf. Client - specializations of this policy may opt to add their own - binding mechanisms, e.g. to allow CastToJS() to work. - - Clients should do any bindings-related cleanup in - Factory::Destruct() or Unwrap(), as appropriate for their - case. - - Ownership of the objects is unchanged by calling this. - - On error, this function may throw a native exception. If - that happens, ClassCreator will call - Unwrap(jsSelf,nativeHandle) and - Factory::Destruct(nativeSelf) to clean up, and will then - propagate the exception. - - The default implementation does nothing. - */ - static void Wrap( v8::Persistent const &, NativeHandle ) - { - return; - } - - /** - This is called from the ClassCreator-generated destructor, - just before the native destructor is called. If nativeSelf - is NULL then it means that native construction failed, - but implementations must (if necessary) clean up any data - stored in jsSelf by the PreWrap() function. - - Specializations may use this to clean up data stored in - other internal fields of the object (_not_ the field used - to hold the native itself - that is removed by the - framework). Optionally, such cleanup may be done in the - corresponding Factory::Destruct() routine, and must be done - there if the dtor will need access to such data. - - Note that when this is called, jsSelf and nativeSelf are - about to be destroyed, so do not do anything crazy with the - contents of jsSelf and DO NOT destroy nativeSelf (that is - the job of the ClassCreator_Factory policy). - - Ownership of the objects is unchanged by calling this. - - Unwrap() is called during destruction or when construction - fails (via a native exception), so any cleanup required for - the jsSelf object can be delegated to this function, as - opposed to being performed (and possibly duplicated) in - PreWrap() and/or Wrap(). - - The default implementation does nothing. - */ - static void Unwrap( v8::Handle const &, NativeHandle ) - { - return; - } - }; - - -#if 0 - namespace Detail - { - template - struct SharedType : public Context - { - private: - SharedType(){} - public: - static SharedType & Instance() - { - static SharedType bob; - return bob; - } - }; - } -#endif - /** - A basic Native-to-JS class binding mechanism. This class does - not aim to be a monster framework, just something simple, - mainly for purposes of showing (and testing) what the core - cvv8 can do. - - The framework must know how to convert JS objects to T objects, - and for this to work client code must define a JSToNative - specialization in this manner: - - @code - template <> - struct JSToNative - : JSToNative_ClassCreator - {}; - @endcode - - If the internal field configuration must be customized then the - client must define the number of fields by - specializing/customizing the ClassCreator_InternalFields - policy class. Additionally, if the client does NOT use the - above JSToNative implementation then he should create his - implementation by subclassing - JSToNative_ObjectWithInternalFields, where (N,M) are the - number of internals fields and the index of the field where the - native object is to be stored. See JSToNative_ClassCreator - for an example. - - TODOs: - - - Certain operations may not work properly when inheriting - bound classes from JS space, and possibly not even when - inheriting bound natives from one another. That depends on - several factors too complex to summarize here. - - - See how much of the v8::juice::cw::ClassWrap - inheritance-related code we can salvage for re-use here. - - - There are known problems when trying to bind inherited methods - when the parent class has no bound them to JS. i'm not sure how - i can fix the templates to get this working. - */ - template - class ClassCreator - { - private: - typedef ClassCreator_InternalFields InternalFields; - typedef ClassCreator_WeakWrap WeakWrap; - typedef ClassCreator_TypeID TypeID; - v8::Persistent ctorTmpl; - v8::Handle protoTmpl; - bool isSealed; - typedef ClassCreator_Factory Factory; - - - /** - A utility function primarily intended to support various - ClassCreator policy implementations. - - This function tries to extract a native handle from jo by - looking in the internal field defined by - ClassCreator_InternalFields::NativeIndex. If a native is - found in that field and it is the same as nh, then jo is - returned. If none is found, jo's prototype object is searched, - recursively, until either nh is found in the prototype chain or - the end of the chain is reached. If a match is found, the JS - object in which the native was found is returned. This does no - casting - it only compares by address. - - If nh is not found anywhere in the chain, an empty handle is - returned. - - Note that T must be non-cv qualified, so it is generally - undesirable to allow the compiler to deduce its type from the - parameter. Thus the T template parameter should not be omitted - from calls to this function. - */ - static v8::Handle FindHolder( v8::Handle const & jo, - T const * nh ) - { - if( !nh || jo.IsEmpty() ) return v8::Handle(); - v8::Handle proto(jo); - void const * ext = NULL; - typedef ClassCreator_SearchPrototypeForThis SPFT; - while( !ext && !proto.IsEmpty() && proto->IsObject() ) - { - v8::Local const & obj( v8::Object::Cast( *proto ) ); - ext = (obj->InternalFieldCount() != InternalFields::Count) - ? NULL - : obj->GetPointerFromInternalField( InternalFields::NativeIndex ); - // FIXME: if InternalFields::TypeIDIndex>=0 then also do a check on that one. - /* - If !ext, there is no bound pointer. If (ext && - (ext!=nh)) then there is one, but it's not the droid - we're looking for. In either case, (possibly) check the - prototype... - */ - if( ext == nh ) return obj; - else if( !SPFT::Value ) break; - else proto = obj->GetPrototype(); - } - return v8::Handle(); - } - - static void weak_dtor( v8::Persistent< v8::Value > pv, void *nobj ) - { - using namespace v8; - //std::cerr << "Entering weak_dtor<>(native="<<(void const *)nobj<<")\n"; - Local jobj( Object::Cast(*pv) ); - typedef typename JSToNative::ResultType NT; - NT native = CastFromJS( pv ); - if( !native ) - { - /* see: http://code.google.com/p/v8-juice/issues/detail?id=27 - - When i call pv.Dispose(), this function is getting called twice, - and the second time won't work. i'm going to igore (return w/o - side-effects) this for now for the sake of avoiding a crash - which i'm seeing only on 64-bit platforms. - - However, even if i return here, v8 is crashing with a - !NEAR_DEATH assertion right after the second call is made. - - The extra pair of Dispose()/Clear() calls seems to eliminate that - crash, but the fact that this code block is hit AT ALL is a - sign of a problem - the dtor shouldn't be called twice! - */ - pv.Dispose(); - pv.Clear(); -#if 1 /* i believe this problem was fixed. If you are reading this b/c - you followed an assert() message, please report this as a bug. - */ - assert( 0 && "weak_dtor() got no native object!"); -#endif - return; - } - else - { - /** - Reminder: the FindHolder() bits are here to - assist when the bound native exists somewhere in the - prototype chain other than jobj itself. In that case, - jobj is valid but we cannot clear out the native handle - internal field on it because it has no internal fields - (or none that belong to us). - - To fix this properly we have to be able to know - _exactly_ which JS object in the prototype chain nh is - bound to. - */ - v8::Handle nholder = FindHolder( jobj, native ); -#if 1 /* reminder: i've never actually seen this error happen, i'm just pedantic about checking... */ - assert( ! nholder.IsEmpty() ); - WeakWrap::Unwrap( nholder /*jobj? subtle difference!*/, native ); - if( nholder.IsEmpty() || (nholder->InternalFieldCount() != InternalFields::Count) ) - { - StringBuffer msg; - msg << "SERIOUS INTERNAL ERROR:\n" - << "ClassCreator::weak_dtor() " - << "validated that the JS/Native belong together, but " - << "FindHolder() returned an " - << (nholder.IsEmpty() ? "empty" : "invalid") - << " handle!\n" - << "From JS=@"<<(void const *)nobj - << ", Converted to Native=@"<<(void const *)native - << ", nholder field count="<InternalFieldCount() - << ", jobj field count="<InternalFieldCount() - << "\nTHIS MAY LEAD TO A CRASH IF THIS JS HANDLE IS USED AGAIN!!!\n" - ; - Factory::Delete(native); - pv.Dispose(); pv.Clear(); /* see comments below!*/ - v8::ThrowException(msg.toError()); - return; - } - else - { - nholder->SetInternalField( InternalFields::NativeIndex, Null() ); - if( 0 <= InternalFields::TypeIDIndex ) - { - nholder->SetInternalField( InternalFields::TypeIDIndex, Null() ); - } - Factory::Delete(native); - } -#else - WeakWrap::Unwrap( nholder, native ); - nholder->SetInternalField( InternalFields::NativeIndex, Null() ); - if( 0 <= InternalFields::TypeIDIndex ) - { - nholder->SetInternalField( InternalFields::TypeIDIndex, Null() ); - } - Factory::Delete(native); -#endif - } - /* - According to the v8 gurus i need to call pv.Dispose() - instead of pv.Clear(), but if i do then this dtor is - being called twice. If i don't call it, v8 is crashing - sometime after this function with a !NEAR_DEATH - assertion. - */ - pv.Dispose(); - pv.Clear(); - } - - /** - Gets installed as the NewInstance() handler for T. - */ - static v8::Handle ctor_proxy( v8::Arguments const & argv ) - { - using namespace v8; - if(ClassCreator_AllowCtorWithoutNew::Value) - { - /** - Allow construction without 'new' by forcing this - function to be called in a ctor context... - */ - if (!argv.IsConstructCall()) - { - const int argc = argv.Length(); - Handle ctor( Function::Cast(*argv.Callee())); - std::vector< Handle > av(static_cast(argc),Undefined()); - for( int i = 0; i < argc; ++i ) av[i] = argv[i]; - return ctor->NewInstance( argc, &av[0] ); - } - } - else - { - /** - Why have this limitation? If we don't, v8 pukes - when the ctor is called, with - "v8::Object::SetInternalField() Writing internal - field out of bounds". - */ - if (!argv.IsConstructCall()) - { - return Toss("This constructor cannot be called as function!"); - } - } - Local const & jobj( argv.This() - /*CastToJS(*nobj) - - We are not yet far enough - along in the binding that - CastToJS() can work. And it - can't work for the generic - case, anyway. - */); - if( jobj.IsEmpty() ) return jobj /* assume exception*/; - Persistent self( Persistent::New(jobj) ); - T * nobj = NULL; - try - { - WeakWrap::PreWrap( self, argv ); - nobj = Factory::Create( self, argv ); - if( ! nobj ) - { - return CastToJS(std::runtime_error("Native constructor failed.")); - } - WeakWrap::Wrap( self, nobj ); - self.MakeWeak( nobj, weak_dtor ); - if( 0 <= InternalFields::TypeIDIndex ) - { - self->SetPointerInInternalField( InternalFields::TypeIDIndex, (void *)TypeID::Value ); - } - self->SetPointerInInternalField( InternalFields::NativeIndex, nobj ) - /* We do this after the call to Wrap() just in case the Wrap() impl - accidentally writes to this field. In that case we end up - losing the data they stored there. So this is just as evil as - adding the internal field before Wrap(), but only when the - client mis-uses the internal fields. - */ - ; - } - catch(std::exception const &ex) - { - WeakWrap::Unwrap( self, nobj ); - if( nobj ) Factory::Delete( nobj ); - self.Clear(); - return Toss(CastToJS(ex)); - } - catch(...) - { - WeakWrap::Unwrap( self, nobj ); - if( nobj ) Factory::Delete( nobj ); - self.Clear(); - return Toss("Native constructor threw an unknown exception!"); - } - return self; - } - - ClassCreator() - : ctorTmpl(v8::Persistent::New( v8::FunctionTemplate::New(ctor_proxy) )), - protoTmpl(v8::Persistent::New( ctorTmpl->PrototypeTemplate() )), - isSealed(false) - { - ctorTmpl->InstanceTemplate()->SetInternalFieldCount(InternalFields::Count); - } - public: - /** - The native type being bound to JS. - */ - typedef typename tmp::PlainType::Type Type; - - /** - Returns the shared instance of this class. - */ - static ClassCreator & Instance() - { - static ClassCreator bob; - return bob; - } - - /** - Returns this class' prototype object. - */ - inline v8::Handle Prototype() - { - return this->protoTmpl; - } - - /** - Returns this class' constructor template object. - */ - inline v8::Handle CtorTemplate() - { - return this->ctorTmpl; - } - - /** - Returns this class' constructor template. - - ACHTUNG: after this is called, changes made to the Prototype() - object might not have any effect. Thus this should only be - called after the prototype object has been fully set up. - (i have no idea why v8 behaves this way.) - - After calling this, IsSealed() will return true. - */ - inline v8::Handle CtorFunction() - { - // In my experience, if GetFunction() is called BEFORE setting up - // the Prototype object, v8 gets very unhappy (class member lookups don't work?). - this->isSealed = true; - return this->ctorTmpl->GetFunction(); - } - - /** - Returns true if CtorFunction() has been called. See that - function for why. - */ - inline bool IsSealed() const - { - return this->isSealed; - } - - /** - Creates a new instanced of the object via the JS API. It calls - ClassCreator_Factory::Create(), passing it argv, to - instantiate the object. On success a JS handle to the object is - returned (it is owned by v8), and the caller can get the native - pointer with: - - @code - T * t = CastFromJS(theHandle); - @endcode - */ - inline v8::Handle NewInstance( int argc, v8::Handle argv[] ) - { - return this->CtorFunction()->NewInstance(argc, argv); - } - - /** - A convenience form of NewInstance() which returns the JS version - of the object and assigns tgt to the native pointer (which will - be NULL on error). - - If tgt is NULL when this function returns, or - returnedObj.IsEmpty(), then we assume that a v8 exception is - propagating, and the caller should return to v8 as soon as - possible so the exception can be triggered JS-side (it is not - actually triggered until we return to v8). - - The returned object is owned by v8. - */ - v8::Handle NewInstance( int argc, v8::Handle argv[], T * & tgt ) - { - v8::Handle const & obj( this->CtorFunction()->NewInstance(argc, argv) ); - if( obj.IsEmpty() ) return obj /* assume exception is propagating. */; - else - { - tgt = CastFromJS(obj); - if( !tgt ) { - Toss(StringBuffer()<<"Internal error: NewInstance() returned a non-empty " - << "Handle but CastFromJS<"<::Value<<">() failed. " - << "This is either a serious cvv8 bug or the JSToNative specialization " - << "is not working properly."); - return v8::Handle(); - } - else return obj; - } - } - - /** - Convenience method to add the given property to the - prototype. Returns this object, for call chaining. - - CastToJS(val) must be valid or a compile-time - error will be triggered. - */ - template - inline ClassCreator & Set( char const * name, ValueT val ) - { - this->protoTmpl->Set(v8::String::New(name), CastToJS(val)); - return *this; - } - //! Not quite sure why i need this overload, but i do. - inline ClassCreator & Set( char const * name, v8::InvocationCallback val ) - { - this->protoTmpl->Set(v8::String::New(name), CastToJS(val)); - return *this; - } - /** - Equivalent to Set(). - */ - template - inline ClassCreator & operator()( char const * name, ValueT val ) - { - return this->Set(name, val); - } - /** - Overload to avoid an ambiguity. - */ - inline ClassCreator & operator()( char const * name, v8::InvocationCallback val ) - { - return this->Set(name, val); - } - - /** - Adds CtorFunction() to dest using the given property name. - This implicitly "seals" the class (see CtorFunction() for - details). - */ - inline void AddClassTo( char const * thisClassName, v8::Handle const & dest ) - { - dest->Set(v8::String::New(thisClassName), - this->CtorFunction()); - } - - /** - Destroys the given object by disconnecting its associated - native object and calling the native destructor function - for it. - - If jo cannot be converted to a T then false is - returned. Otherwise the true is returned and the native - object referenced by jo is no longer valid (it should not - be used by JS code). - - Native functions bound to that object should take care to - bail out with an exception once the native pointer is gone, - as opposed to blindly stepping on its null/dangling pointer - (which _might_ have been re-allocated to a different - object, even of a different type, in the mean time). - */ - static bool DestroyObject( v8::Handle const & jo ) - { - T * t = CastFromJS(jo); - if( ! t ) return false; - else - { - v8::Persistent p( v8::Persistent::New( jo ) ); - p.ClearWeak(); // avoid a second call to weak_dtor() via gc! - weak_dtor( p, t ); - return true; - } - } - /** - If jv is empty or !jv->IsObject() then false is returned, - otherwise it returns the result of - DestroyObject(Handle). - */ - static bool DestroyObject( v8::Handle const & jv ) - { - return (jv.IsEmpty() || !jv->IsObject()) - ? false - : DestroyObject( v8::Handle( v8::Object::Cast(*jv) ) ); - } - - /** - A v8::InvocationCallback implementation which calls - DestroyObject( argv.This() ). - - It is intended to be used as a "manual destructor" for - classes which need it. The canonical examples are - Stream.close() and Database.close(). - - This function is not called DestroyObject to avoid name - collisions during binding using Set(...,DestroyObjectCallback). - */ - static v8::Handle DestroyObjectCallback( v8::Arguments const & argv ) - { - return DestroyObject(argv.This()) ? v8::True() : v8::False(); - } - - /** - Tells v8 that this bound type inherits ParentType. - ParentType _must_ be a class wrapped by ClassCreator. - This function throws if - ClassCreator::Instance().IsSealed() returns - false). We require that the parent class be sealed to - avoid accidental mis-use caused by registering a - subclass of a class which has not yet been bound (and may - may never be bound). - */ - template - void Inherit() - { - typedef ClassCreator PT; - PT & p(PT::Instance()); - if( ! p.IsSealed() ) - { - throw std::runtime_error("ClassCreator has not been sealed yet!"); - } - this->CtorTemplate()->Inherit( p.CtorTemplate() ); - } - - /** - Simply runs ClassCreator_SetupBindings::Initialize( target ). - It is provided here to simplify the client-side interface. - */ - static void SetupBindings( v8::Handle const & target ) - { - ClassCreator_SetupBindings::Initialize( target ); - } - - }; - - /** - Intended to be the base class for JSToNative specializations - when T is JS-bound using ClassCreator. - - This particular implementation must be defined _after_ - any of the following policies are customized for T: - - - ClassCreator_InternalFields - - ClassCreator_SearchPrototypeForThis - - ClassCreator_TypeID (only if TypeSafe is true!) - - If the client will not specialize those types type then the order is - irrelevant, but when specializing any of them, they must come before - this JSToNative implementation is instantiated. - - If TypeSafe is true then this type is a proxy for - JSToNative_ObjectWithInternalFieldsTypeSafe, else it is a proxy for - JSToNative_ObjectWithInternalFields. Note that ClassCreator is - hard-wired to implant/deplant type id information if - ClassCreator_InternalFields::TypeIDIndex is not negative, with the - _hope_ that JSToNative will use it, but it does not enforce that - the type ID is used. For types where the internal fields' TypeIDIndex - is negative, ClassCreator will not set up bits for the type check, - which means a slightly smaller runtime memory footprint. - */ - template ::TypeIDIndex >= 0 > - struct JSToNative_ClassCreator : - tmp::IfElse< TypeSafe, - JSToNative_ObjectWithInternalFieldsTypeSafe::Value, - ClassCreator_InternalFields::Count, - ClassCreator_InternalFields::TypeIDIndex, - ClassCreator_InternalFields::NativeIndex, - ClassCreator_SearchPrototypeForThis::Value - >, - JSToNative_ObjectWithInternalFields::Count, - ClassCreator_InternalFields::NativeIndex, - ClassCreator_SearchPrototypeForThis::Value - > - >::Type - { - }; - -#if 0 - //! Experimental. - template - struct JSToNative_ClassCreator_Subclass - { - typedef typename TypeInfo::NativeHandle ResultType; - ResultType operator()( v8::Handle const & h ) const - { - typedef typename TypeInfo::NativeHandle PTP; - PTP typeCheck; typeCheck = (ResultType)NULL - /* If compiler errors led you here then SubT probably does not - publicly subclass ParentT. */ - ; - PTP p = CastFromJS(h); - //std::cerr << "dyncast="<(p)<<"\n"; - return p ? dynamic_cast(p) : NULL; - } - }; -#endif - -#if !defined(DOXYGEN) - namespace Detail - { - /** - A base class for ClassCreator_Factory_CtorArityDispatcher. - We don't really need this level of indirection, i think. - */ - template - struct Factory_CtorForwarder_Base - { - typedef typename TypeInfo::Type Type; - typedef typename TypeInfo::NativeHandle NativeHandle; - static void Delete( NativeHandle nself ) - { - delete nself; - } - protected: - /** - If argv.Length() >= Arity then this function ignores errmsg and - returns true, otherwise it writes a descriptive error message - to errmsg and return false. - */ - static bool argv_check( v8::Arguments const & argv, int Arity ) - { - if( argv.Length() >= Arity ) return true; - else - { - StringBuffer msg; - msg << "constructor requires " << Arity << " arguments!"; - throw std::range_error(msg.Content().c_str()); - return false; - } - } - }; - } -#endif // !DOXYGEN - - /** - Can be used as a concrete ClassCreator_Factor - specialization to forward JS ctor calls directly to native - ctors. - - T must be the ClassCreator'd type to construct. CtorProxy must - be a type having this interface: - - @code - TypeInfo::NativeHandle Call( v8::Arguments const & ); - @endcode - - Normally CtorProxy would be CtorForwarder or CtorArityDispatcher, - but any interface-compatible type will do. - - It must return a new object instance on success. On error it - may return NULL and "should" throw a native exception explaining - the problem. The exception will be caught by ClassCreator and - transformed into a JS-side exception. - - If CtorProxy::Call() succeeds (returns non-NULL and does not throw) - then NativeToJSMap is used to create a native-to-JS mapping. - To make use of this, the client should do the following: - - @code - // in the cvv8 namespace: - template <> - struct NativeToJS : NativeToJSMap::NativeToJSImpl {}; - @endcode - - After that, CastToJS( theNativeObject ) can work. - - The mapping is cleaned up when (if!) the object is sent through - the JS garbage collector or the client somehow triggers its - JS-aware destruction (e.g. via ClassCreator::DestroyObject(), - assuming the type was wrapped using ClassCreator). - */ - template - struct ClassCreator_Factory_NativeToJSMap : Detail::Factory_CtorForwarder_Base - { - public: - typedef NativeToJSMap N2JMap; - typedef typename TypeInfo::Type Type; - typedef typename TypeInfo::NativeHandle NativeHandle; - - /** - If CtorProxy::Call(argv) succeeds, N2JMap::Insert(jself, theNative) - is called. The result of CtorProxy::Call() is returned. - */ - static NativeHandle Create( v8::Persistent jself, v8::Arguments const & argv ) - { - NativeHandle n = CtorProxy::Call( argv ); - if( n ) N2JMap::Insert( jself, n ); - return n; - } - /** - Calls N2JMap::Remove( nself ) then (delete nself). - */ - static void Delete( NativeHandle nself ) - { - N2JMap::Remove( nself ); - delete nself; - } - }; - - /** @deprecated Use ClassCreator_Factory_Dispatcher instead (same interface). - */ - template - struct ClassCreator_Factory_CtorArityDispatcher : Detail::Factory_CtorForwarder_Base - { - public: - typedef typename TypeInfo::Type Type; - typedef typename TypeInfo::NativeHandle NativeHandle; - static NativeHandle Create( v8::Persistent , v8::Arguments const & argv ) - { - typedef CtorArityDispatcher Proxy; - return Proxy::Call( argv ); - } - }; - - /** - A ClassCreator_Factory implementation which forwards its Create() - member to CtorT::Call() (the interface used by CtorForwarder and friends). - - T must (or is assumed to) be a ClassCreator-wrapped class. - CtorForwarderList must be a Signature typelist of CtorForwarder - types and its "return type" must be T (optionally pointer-qualified). - - Example: - - @code - typedef CtorForwarder C0; - typedef CtorForwarder C1; - typedef CtorForwarder C2; - typedef Signature< CFT (C0, C1, C2) > CtorList; - - // Then create Factory specialization based on those: - template <> - struct ClassCreator_Factory : - ClassCreator_Factory_Dispatcher > {}; - @endcode - - Or: - - @code - template <> - struct ClassCreator_Factory : - ClassCreator_Factory_Dispatcher< MyType, CtorForwarder > - {}; - @endcode - */ - template - struct ClassCreator_Factory_Dispatcher : Detail::Factory_CtorForwarder_Base - { - public: - typedef typename TypeInfo::Type Type; - typedef typename TypeInfo::NativeHandle NativeHandle; - static NativeHandle Create( v8::Persistent jself, v8::Arguments const & argv ) - { - return CtorT::Call( argv ); - } - }; - - -}// namespaces - -#endif /* CODE_GOOGLE_COM_P_V8_CONVERT_CLASS_CREATOR_HPP_INCLUDED */ diff --git a/vendor/libv8-convert/cvv8/Makefile b/vendor/libv8-convert/cvv8/Makefile deleted file mode 100644 index 552c1ebd4..000000000 --- a/vendor/libv8-convert/cvv8/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -all: - -EXAMPLE_DIR := ../../examples -ifneq (,$(wildcard $(EXAMPLE_DIR)/Makefile)) -$(sort all $(MAKECMDGOALS)): - $(MAKE) -C ../../examples $@ -endif - diff --git a/vendor/libv8-convert/cvv8/NativeToJSMap.hpp b/vendor/libv8-convert/cvv8/NativeToJSMap.hpp deleted file mode 100644 index 1e09da7bd..000000000 --- a/vendor/libv8-convert/cvv8/NativeToJSMap.hpp +++ /dev/null @@ -1,183 +0,0 @@ -#if ! defined(V8_CONVERT_NATIVE_JS_MAPPER_HPP_INCLUDED) -#define V8_CONVERT_NATIVE_JS_MAPPER_HPP_INCLUDED - -#include "detail/convert_core.hpp" -namespace cvv8 { - /** - A helper class to assist in the "two-way-binding" of - natives to JS objects. This class holds native-to-JS - binding information. - - In the general case, a native-to-JS conversion is only - needed at the framework-level if bound/converted - functions/methods will _return_ bound native - pointers/references. If they only return "core" types (numbers - and strings, basically), or explicitly return v8-supported - types (e.g. v8::Handle) then no native-to-JS - conversion is typically needed. - - Known limitations: - - This type does not fully support subclass conversions. - e.g. the following function binding: - - @code - virtual MyType * (MyType::*)(); - @endcode - - _should_ be able to return a MySubType from derived implementations - but it currently cannot. Handling this requires that a parent class - be told each of its subclasses, and that we add internal handlers - which try lookups on those classes if a conversion to MyType fails. - - Reminder to self: the v8::juice tree has an example of that which we - can probably plunder. - */ - template - struct NativeToJSMap - { - private: - typedef TypeInfo TI; - typedef typename TI::Type Type; - /** - The native type to bind to. - */ - typedef typename TI::NativeHandle NativeHandle; - /** The type for holding the JS 'this' object. */ - typedef v8::Persistent JSObjHandle; - //typedef v8::Handle JSObjHandle; // Hmmm. - typedef std::pair ObjBindT; - typedef std::map OneOfUsT; - /** Maps (void const *) to ObjBindT. - - Reminder to self: we might need to make this map a static - non-function member to work around linking problems (at - least on Windows) which lead to multiple instances of - the returned map being created when the types being - bound are loaded from multiple DLLs. The out-of-class - initialization of the member is going to require a really - ugly set of template parameters, though. - */ - static OneOfUsT & Map() - { - static OneOfUsT bob; - return bob; - } - public: - /** Maps obj as a lookup key for jself. Returns false if !obj, - else true. */ - static bool Insert( JSObjHandle const & jself, - NativeHandle obj ) - { - return obj - ? (Map().insert( std::make_pair( obj, std::make_pair( obj, jself ) ) ),true) - : 0; - } - - /** - Removes any mapping of the given key. Returns the - mapped native, or 0 if none is found. - */ - static NativeHandle Remove( void const * key ) - { - typedef typename OneOfUsT::iterator Iterator; - OneOfUsT & map( Map() ); - Iterator it = map.find( key ); - if( map.end() == it ) - { - return 0; - } - else - { - NativeHandle victim = (*it).second.first; - map.erase(it); - return victim; - } - } - - /** - Returns the native associated (via Insert()) - with key, or 0 if none is found. - */ - static NativeHandle GetNative( void const * key ) - { - if( ! key ) return 0; - else - { - typename OneOfUsT::iterator it = Map().find(key); - return (Map().end() == it) - ? 0 - : (*it).second.first; - } - } - - /** - Returns the JS object associated with key, or - an empty handle if !key or no object is found. - */ - static v8::Handle GetJSObject( void const * key ) - { - if( ! key ) return v8::Handle(); - typename OneOfUsT::const_iterator it = Map().find(key); - if( Map().end() == it ) return v8::Handle(); - else return (*it).second.second; - } - - /** - A base NativeToJS implementation for classes which use NativeToJSMap - to hold their native-to-JS bindings. To be used like this: - - @code - // must be in the v8::convert namespace! - template <> - struct NativeToJS : NativeToJSMap::NativeToJSImpl {}; - @endcode - */ - struct NativeToJSImpl - { - v8::Handle operator()( Type const * n ) const - { - typedef NativeToJSMap BM; - v8::Handle const & rc( BM::GetJSObject(n) ); - if( rc.IsEmpty() ) return v8::Null(); - else return rc; - } - v8::Handle operator()( Type const & n ) const - { - return this->operator()( &n ); - } - }; - -#if 0 - //! Experimental - template - struct NativeToJSImpl_Subclass - { - v8::Handle operator()( Type const * n ) const - { - typedef NativeToJSMap BM; - v8::Handle const & rc( BM::GetJSObject(n) ); - if( rc.IsEmpty() ) - { - typedef typename NativeToJSMap::NativeToJSImpl PI; - return PI()(n); -#if 0 - typedef typename TypeInfo::NativeHandle PH; - rc = CastToJS(n); - if( rc.IsEmpty() ) return v8::Null(); - else return rc; -#endif - } - else return rc; - } - v8::Handle operator()( Type const & n ) const - { - return this->operator()( &n ); - } - }; -#endif - }; - -} // namespaces - -#endif /* include guard */ diff --git a/vendor/libv8-convert/cvv8/V8Shell.hpp b/vendor/libv8-convert/cvv8/V8Shell.hpp deleted file mode 100644 index ecfb9aa3a..000000000 --- a/vendor/libv8-convert/cvv8/V8Shell.hpp +++ /dev/null @@ -1,650 +0,0 @@ -#if !defined(V8_CONVERT_V8Shell_HPP_INCLUDED) -#define V8_CONVERT_V8Shell_HPP_INCLUDED -/** @file V8Shell.hpp - - This file contains the v8::convert::V8Shell class, a convenience - wrapper for bootstrapping integration of v8 into arbitrary - client applications. - - Dependencies: v8 and the STL. - - License: released into the Public Domain by its author, - Stephan Beal (http://wanderinghorse.net/home/stephan/). -*/ -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace cvv8 { - namespace Detail { - template - struct V8MaybeLocker - { - private: - v8::Locker lock; - public: - V8MaybeLocker() : lock() {} - }; - template <> - struct V8MaybeLocker - { - }; - } - /** - This class implements a very basic shell for v8. - - - These objects are basically thin wrappers around the - bootstrap code necessary for getting v8 running in an - application. They are intended to be stack-created in main() - (or equivalent) and used as a front-end for passing JS code - into v8 for execution. - - Because library-level JS code activated via this class - _might_ use v8::Unlocker to unlock the VM while C-level - routines are running, each instance of this class includes a - v8::Locker instance if UseLocker is true. (If it did not, - clients would be required to add one or accept crashes when - called code uses v8::Unlocker.) Only set UseLocker to false - if you _know_ that _no_ JS code run through this API will - end up trying to unlock v8. (If you're using this class - together with the v8::convert function binding API then you - are almost certainly using v8::Unlocker without realizing it.) - - Maintenance reminder: keep this class free of dependencies - on other library-level code so that we can re-use it - in arbitrary v8 clients. - - FIXME: the way this class uses v8::TryCatch is "all wrong", and any - functions using it need to be revisited. - */ - template - class V8Shell - { - public: - /** - A callback function signature for reporing JS-side - exception messages to the native world. - - TODO: consider passing a v8::Handle argument - instead of a (char const *) and possibly a (void *) State - handle for use by the client. - */ - typedef void (*ErrorMessageReporter)( char const * msg ); - private: - // The declaration order of the v8-related objects is important! - Detail::V8MaybeLocker locker; - v8::HandleScope hscope; - //v8::Handle globt; - v8::Handle context; - v8::Context::Scope cxscope; - v8::Handle global; - /** - tryCatch is only here until i can track down a post-main() - v8 assertion which happens when V8Shell-executed JS code - exits with an exception. It is just a workaround. - */ - v8::TryCatch tryCatch; - ErrorMessageReporter reporter; - static void DefaultErrorMessageReporter( char const * msg ) - { - if( msg && *msg ) std::cerr - //<< "[V8Shell default exception reporter says:]\n" - << msg << std::endl; - } - - /** - An v8::InvocationCallback implementation which implements a - JS-conventional print() routine. OS must be a pointer to - an ostream, e.g. std::cout or std::cerr. - - Each argument is converted to a string (using - v8::String::Utf8Value) and is output, separated by a - space. For compatibility with other toolkits' print() - implementations (some of which only accept one - argument), it is recommended that client script code - only rely on the first argument being output. - - Always returns v8::Undefined(). - - It is a little-known fact that one can replace the output - buffer used by std::cout (and other std::ostreams) with a - custom one, such that calling print() from JS code will - redirect the output to a different destination. This can - be used, e.g., to redirect std::cout to a libcurses window. - */ - template - static v8::Handle PrintToStdOstream( v8::Arguments const & argv ) - { - v8::HandleScope hscope; - int const argc = argv.Length(); - const char * cstr = NULL; - for (int i = 0; i < argc; i++) - { - if( 0 != i ) *OS << ' '; - v8::String::Utf8Value const str(argv[i]); - cstr = *str; - if( cstr ) *OS << cstr; - } - *OS << '\n'; - OS->flush(); - return v8::Undefined(); - } - - void init( char const * globalObjectName, - int argc, char const * const * argv, - unsigned short argOffset ) - { - if( globalObjectName && *globalObjectName ) - { - this->global->Set( v8::String::New(globalObjectName), this->global ); - } - if( (0 < argc) && (NULL != argv) ) - { - this->ProcessMainArgv( argc, argv, argOffset ); - } - } - - static void SetupTryCatch( v8::TryCatch & tc ) - { - tc.SetVerbose(true); - tc.SetCaptureMessage(true); - } - public: - /** - Initialize a v8 context and global object belonging to this object. - - If globalObjectName is not null and not empty then the global object - is given a refernce to itself using the given name, such that client - JS code can then refer to it. - - If argc is greater than 0 and argv is not NULL then argv is - assumed to be an arguments list in the format conventional - for main() and ProcessMainArgv(argc,argv,argOffset) is called. - */ - V8Shell( char const * globalObjectName = NULL, - int argc = 0, char const * const * argv = NULL, - unsigned short argOffset = 1 ) : - locker(), - hscope(), - //globt( v8::ObjectTemplate::New() ), - context( v8::Context::New(NULL, v8::ObjectTemplate::New()) ), - cxscope(context), - global( context->Global() ), - reporter( DefaultErrorMessageReporter ) - { - this->init( globalObjectName, argc, argv, argOffset ); - } - - /** - Destructs all v8 resources used by this object, e.g. the JS context. - */ - ~V8Shell() - { - if( ! v8::V8::IsDead() ) { - tryCatch.Reset(); - } - } - - /** - Sets the error reporter function used by - ExecuteString(). Passing 0 will disable exception - reporting. The default reporter sends its output to - std::cerr. - */ - void SetExecuteErrorReporter( ErrorMessageReporter r ) - { - this->reporter = r; - } - - /** - Outputs an exception message using the current - error reporter function. - - If try_catch or the current error reporter are - null then nothing is done. - - @see SetExecuteErrorReporter(). - */ - - void ReportException(v8::TryCatch* try_catch) - { - if( !try_catch || ! this->reporter ) return; - v8::HandleScope hsc; - v8::String::Utf8Value const excUtf(try_catch->Exception()); -#define TOCSTR(X) (*X ? *X : "") - const char* excCstr = TOCSTR(excUtf); - v8::Handle const & message( try_catch->Message() ); - std::ostringstream os; - os << "V8Shell Exception Reporter: "; - if (message.IsEmpty()) - { - // V8 didn't provide any extra information about this error; just - // print the exception. - os << excCstr << '\n'; - } - else - { - // output (filename):(line number): (message)... - int linenum = message->GetLineNumber(); - os << *v8::String::Utf8Value(message->GetScriptResourceName()) << ':' - << std::dec << linenum << ": " - << excCstr << '\n'; - // output source code line... - os << *v8::String::AsciiValue(message->GetSourceLine()) << '\n'; - // output decoration pointing to error location... - int start = message->GetStartColumn(); - for (int i = 0; i < start; i++) { - os << '-'; - } - int end = message->GetEndColumn(); - for (int i = start; i < end; i++) { - os << '^'; - } - os << '\n'; - } - std::string const & str( os.str() ); - this->reporter( str.c_str() ); -#undef TOCSTR - } - - /** - Adds the given function to the global object. - - Returns this object. - */ - V8Shell & operator()( char const * name, v8::Handle const & f ) - { - this->global->Set( v8::String::New(name), f ); - return *this; - } - - /** - Adds the given function to the global object. - - Returns this object. - */ - V8Shell & operator()( char const * name, v8::Handle const & f ) - { - return this->operator()( name, f->GetFunction() ); - } - - /** - Adds the given function to the global object. - - Returns this object. - */ - V8Shell & operator()( char const * name, v8::InvocationCallback const f ) - { - return this->operator()( name, v8::FunctionTemplate::New(f) ); - } - - /** - Returns the global object for this shell. - */ - v8::Handle Global() - { - return this->global; - } - - /** - Returns the context object for this shell. - */ - v8::Handle Context() - { - return this->context; - } - -#if 0 // changes made to global ObjectTemplate have no effect after cx is set up. - v8::Handle GlobalTemplate() - { - return this->globt; - } -#endif - - /** - Intended to be called from main() and passed the argc/argv - which are passed to main. offset is the number of arguments - to skip, and defaults to one to skip the argv[0] argument, - which is conventionally the application name. - - It skips all arguments up to "--". For each argument after - "--", it adds the argument to a list. At the end of the - list, the global object is assigned a property named - "arguments" which contains that list. - - If the argument list has no arguments after a "--" entry - then the "arguments" global value will be an empty array, - as opposed to null or undefined. - - This function does no interpretation of the arguments. - */ - V8Shell & ProcessMainArgv( int argc, char const * const * _argv, unsigned short offset = 1 ) - { - if( (argc<1) || !_argv ) return *this; - char const * endofargs = "--"; - v8::Handle argv( v8::Array::New() ); - int i = (int)offset; - for( ; i < argc; ++i ) - { - if( 0 == strcmp(_argv[i],endofargs) ) - { - ++i; - break; - } - } - int ndx = 0; - for( ; i < argc; ++i ) - { - char const * arg = _argv[i]; - if( arg ) - { // String::New() calls strlen(), which hates NULL - argv->Set( ndx++, v8::String::New(arg) ); - } - } - this->global->Set( v8::String::New("arguments"), argv ); - return *this; - } - - /** - Executes the given source string in the current - context. - - If the script throws an exception then a TryCatch object is used - to build an error string, which is passed to this object's error - reporter function. The default sends the output to std::cerr. - - If resultGoesTo is not null and the result a valid handle, then - the result is converted to a string and sent to that stream. - - Returns the result of the last expression evaluated in the script, - or an empty handle on error. - */ - v8::Handle ExecuteString(v8::Handle const & source, - v8::Handle name, - std::ostream * out = NULL ) - { - //this->executeThrew = false; - v8::HandleScope scope; - v8::TryCatch tc; - SetupTryCatch(tc); - v8::Handle script = v8::Script::Compile(source, name); - if( script.IsEmpty())//tc.HasCaught()) - { - // Report errors that happened during compilation. - //this->executeThrew = true; - this->ReportException(&tc); - return scope.Close(tc.ReThrow()); - //return v8::Handle(); - } - else - { - v8::Handle const & result( script->Run() ); - if( tc.HasCaught())//(result.IsEmpty()) - { - //this->executeThrew = true; - this->ReportException(&tc); - //return v8::Handle(); - return scope.Close(tc.ReThrow()); - } - else - { - if (out && !result.IsEmpty()) - { - (*out) << *v8::String::Utf8Value(result) << '\n'; - } - return scope.Close(result); - } - } - } - -#if 0 - bool ExecThrewException() const - { - return this->executeThrew; - } -#endif - - /** - Convenience form of ExecuteString(source,"some default name", reportExceptions, 0). - */ - v8::Handle ExecuteString(std::string const & source, - std::string const & name, - std::ostream * resultGoesTo ) - { - v8::HandleScope scope; - v8::Local const & s( v8::String::New( source.c_str(), static_cast(source.size()) ) ); - v8::Local const & n( v8::String::New( name.c_str(), static_cast(name.size()) ) ); - return scope.Close(this->ExecuteString( s, n, resultGoesTo )); - } - - /** - Convenience overload taking input from a native string. - */ - v8::Handle ExecuteString(std::string const & source ) - { - return this->ExecuteString(source, "ExecuteString()", 0); - } - - /** - Convenience form of ExecuteString(source,"some default name", 0, reportExceptions). - */ - v8::Handle ExecuteString(v8::Handle source ) - { - return this->ExecuteString(source, v8::String::New("ExecuteString()"), 0); - } - - /** - Convenience form of ExecuteString() reading from an opened input stream. - - Throws a std::exception if reading fails or the input is empty. - - An empty input is not necessarily an error. Todo: re-think this decision. - */ - v8::Handle ExecuteStream( std::istream & is, std::string const & name, - std::ostream * resultGoesTo = NULL ) - { - std::ostringstream os; - is >> std::noskipws; - std::copy( std::istream_iterator(is), std::istream_iterator(), std::ostream_iterator(os) ); - std::string const & str( os.str() ); - if( str.empty() ) - { - std::ostringstream msg; - msg << "Input stream ["<ExecuteString( str, name, resultGoesTo ); - } - - /** - Convenience form of ExecuteString() reading from a local file. - */ - v8::Handle ExecuteFile( char const * filename, - std::ostream * resultGoesTo = NULL ) - { - if( ! filename || !*filename ) - { - throw std::runtime_error("filename argument must not be NULL/empty."); - } - std::ifstream inf(filename); - if( ! inf.good() ) - { - // FIXME: throw a v8 exception and report it via our reporter. - // Nevermind: the result is useless b/c the exception has no proper vm stack/state info here... - std::ostringstream msg; - msg << "Could not open file ["<ExecuteStream( inf, filename, resultGoesTo ); - } - - /** - An v8::InvocationCallback implementation which implements - a JS-conventional print() routine, sending its output to - std::cout. See PrintToStdOstream() for the exact semantics - argument/return. - */ - static v8::Handle PrintToCout( v8::Arguments const & argv ) - { - return PrintToStdOstream<&std::cout>( argv ); - } - - /** - Identical to PrintToCout(), but sends its output to - std::cerr instead. - */ - static v8::Handle PrintToCerr( v8::Arguments const & argv ) - { - return PrintToStdOstream<&std::cerr>( argv ); - } - - private: - static v8::Handle Include( v8::Arguments const & argv ) - { - int const argc = argv.Length(); - if( argc < 1 ) return v8::Undefined(); - v8::HandleScope hsc; - v8::Local const jvself(argv.Data()); - if( jvself.IsEmpty() || !jvself->IsExternal() ) - { - return v8::ThrowException(v8::Exception::Error(v8::String::New("Include() callback is missing its native V8Shell object."))); - } - V8Shell * self = static_cast( v8::External::Cast(*jvself)->Value() ); - v8::String::Utf8Value fn(argv[0]); - try - { - return hsc.Close(self->ExecuteFile( *fn )); - } - catch( std::exception const & ex ) - { - char const * msg = ex.what(); - return v8::ThrowException(v8::Exception::Error(v8::String::New(msg ? msg : "Unspecified native exception."))); - } - } - - public: - /** - Returns a Function object implementing conventional - include(filename) functionality (called load() in some JS - shells). This function must be created dynamically - because the generated function internally refers back to - this object (so that we can re-use ExecuteString() for the - implementation). - - The return value of the Function is the value of the last - expression evaluated in the given JS code. - - Results are undefined, and almost certainly fatal, if - the generated function is ever called after this native - object has been destructed. For best results, to avoid - potential lifetime issues, never install the returned - function in any object other than this object's Global(). - */ - v8::Handle CreateIncludeFunction() - { - return v8::FunctionTemplate::New(Include, v8::External::New(this))->GetFunction(); - } - - /** - Implements the v8::InvocationCallback interface and has the - following JS interface: - - @code - Array getStracktrace([unsigned int limit = some reasonable default]) - @endcode - - Each element in the returned array represents a stack frame and - is a plain object with the following properties: - - column = 1-based column number (note that this is - different from most editors, but this is how v8 returns - this value). - - line = 1-based line number - - scriptName = name of the script - - functionName = name of the function - - isConstructor = true if this is a constructor call - - isEval = true if this is part of an eval() - - TODO: - - - Add a toString() member to the returned array which creates a - conventional-looking stacktrace string. - */ - static v8::Handle GetStackTrace( v8::Arguments const & argv ) - { - using namespace v8; - int32_t limitSigned = (argv.Length() > 0) ? argv[0]->Int32Value() : 0; - if( limitSigned <= 0 ) limitSigned = 8; - else if( limitSigned > 100 ) limitSigned = 100; - uint32_t limit = static_cast(limitSigned); - HandleScope hsc; - Local const st = StackTrace::CurrentStackTrace( limit, StackTrace::kDetailed ); - int const fcountI = st->GetFrameCount(); - // Who the hell designed the StackTrace API to return an int in GetFrameCount() but take - // an unsigned int in GetFrame()??? - uint32_t const fcount = static_cast(fcountI); - Local jst = Array::New(fcount); -#define STR(X) v8::String::New(X) - for( uint32_t i = 0; (i < fcount) && (i const & sf( st->GetFrame(i) ); - Local jsf = Object::New(); - jsf->Set(STR("column"), v8::Integer::New(sf->GetColumn())); - jsf->Set(STR("functionName"), sf->GetFunctionName()); - jsf->Set(STR("line"), v8::Integer::New(sf->GetLineNumber())); - jsf->Set(STR("scriptName"), sf->GetScriptName()); - jsf->Set(STR("isConstructor"), sf->IsConstructor() ? v8::True() : v8::False() ); - jsf->Set(STR("isEval"), sf->IsEval() ? v8::True() : v8::False() ); - jst->Set(i,jsf); - } - return hsc.Close(jst); -#undef STR - } - - /** - Can optionally be called to include the following functionality - in this shell's Global() object: - - JS Functions: - - print(...) (see PrintToCout()) - - getStacktrace([int limit]) (see GetStackTrace()) - - load(filename) (see CreateIncludeFunction()) - - Returns this object, for use in chaining. - */ - V8Shell & SetupDefaultBindings() - { - (*this)( "print", PrintToCout ) - ("getStacktrace", GetStackTrace) - ("load", this->CreateIncludeFunction()) - ; - return *this; - } - }; - - /** - Convenience typedef for V8Shell<>. - */ - typedef V8Shell<> Shell; - -} -#endif /* V8_CONVERT_V8Shell_HPP_INCLUDED */ diff --git a/vendor/libv8-convert/cvv8/XTo.hpp b/vendor/libv8-convert/cvv8/XTo.hpp deleted file mode 100644 index f3502063e..000000000 --- a/vendor/libv8-convert/cvv8/XTo.hpp +++ /dev/null @@ -1,281 +0,0 @@ -#if !defined (CVV8_TO_X_HPP_INCLUDED) -#define CVV8_TO_X_HPP_INCLUDED -#include "invocable.hpp" -#include "properties.hpp" -/** @file XTo.hpp - - This file provides an alternate approach to the function - conversion API. It covers: - - - Converting functions and methods to to v8::InvocationCallback, - v8::AccessorGetter, and v8::AccessorSetter. - - - Converting variables to v8::AccessorGetter and v8::AccessorSetter. - - All conversions of a given category, e.g. FunctionToXYZ or MethodToXYZ - have a common template, e.g. FunctionTo or MethodTo. The first type - passed to that template is a "tag" type which tells us what conversion - to perform. e.g. a function can be used as an v8::InvocationCallback, - v8::AccessorGetter, or v8::AccessorSetter. - - An example probably explains it best: - - @code - int aBoundInt = 3; - void test_to_bindings() - { - v8::InvocationCallback cb; - v8::AccessorGetter g; - v8::AccessorSetter s; - - using namespace cvv8; - - typedef FunctionTo< InCa, int(char const *), ::puts> FPuts; - typedef FunctionTo< Getter, int(void), ::getchar> GetChar; - typedef FunctionTo< Setter, int(int), ::putchar> SetChar; - cb = FPuts::Call; - g = GetChar::Get; - s = SetChar::Set; - - typedef VarTo< Getter, int, &aBoundInt > VarGet; - typedef VarTo< Setter, int, &aBoundInt > VarSet; - g = VarGet::Get; - s = VarSet::Set; - typedef VarTo< Accessors, int, &aBoundInt > VarGetSet; - g = VarGetSet::Get; - s = VarGetSet::Set; - - typedef BoundNative T; - typedef MethodTo< InCa, const T, int (), &T::getInt > MemInCa; - typedef MethodTo< Getter, const T, int (), &T::getInt > MemGet; - typedef MethodTo< Setter, T, void (int), &T::setInt > MemSet; - cb = MemInCa::Call; - g = MemGet::Get; - s = MemSet::Set; - } - @endcode - - This unconventional, but nonetheless interesting and arguably - very readable/writable approach was first proposed by Coen - Campman. -*/ - - -namespace cvv8 { - - /** - Base (unimplemented) FunctionTo interface. - - Specializations act as proxies for FunctionToInCa, - FunctionToGetter and FunctionToSetter. Tag must be one of - (InCa, InCaVoid, Getter, Setter). The other args are as - documented for the aforementioned proxied types. - - See FunctionToInCa for more information about the parameters. - */ - template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< FunctionSignature >::Value > - struct FunctionTo DOXYGEN_FWD_DECL_KLUDGE; - - //! Behaves like FunctionToInCa. - template ::FunctionType Func, bool UnlockV8> - struct FunctionTo< InCa, Sig, Func, UnlockV8 > : FunctionToInCa - {}; - - //! Behaves like FunctionToInCaVoid. - template ::FunctionType Func, bool UnlockV8> - struct FunctionTo< InCaVoid, Sig, Func, UnlockV8 > : FunctionToInCaVoid - {}; - - //! Behaves like FunctionToGetter. - template ::FunctionType Func, bool UnlockV8> - struct FunctionTo< Getter, Sig, Func, UnlockV8 > : FunctionToGetter - {}; - - //! Behaves like FunctionToSetter. - template ::FunctionType Func, bool UnlockV8> - struct FunctionTo< Setter, Sig, Func, UnlockV8 > : FunctionToSetter - {}; - - /** @class VarTo - - Base (unimplemented) VarTo interface. - - Acts as a proxy for VarToGetter and VarToSetter. Tag must be - one of (Getter, Setter, Accessors). The other args are as - documented for VarToGetter and VarToSetter. - */ - template - struct VarTo DOXYGEN_FWD_DECL_KLUDGE; - - //! Behaves like VarToGetter. - template - struct VarTo< Getter, PropertyType,SharedVar> : VarToGetter - {}; - - //! Behaves like VarToSetter. - template - struct VarTo< Setter, PropertyType,SharedVar> : VarToSetter - {}; - - //! Behaves like VarToAccessors. - template - struct VarTo< Accessors, PropertyType,SharedVar> : VarToAccessors - {}; - - /** - Base (unimplemented) type for MemberTo-xxx conversions. - - Acts as a proxy for MemberToGetter, MemberToSetter and - MemberToAccessors. Tag must be one of (Getter, Setter, Accessors). - The other args are as documented for MemberToGetter and - MemberToSetter. - */ - template - struct MemberTo DOXYGEN_FWD_DECL_KLUDGE; - - //! Behaves like MemberToGetter. - template - struct MemberTo : MemberToGetter< T, PropertyType, MemVar > {}; - - //! Behaves like MemberToSetter. - template - struct MemberTo : MemberToSetter< T, PropertyType, MemVar > {}; - - //! Behaves like MemberToAccessors. - template - struct MemberTo : MemberToAccessors< T, PropertyType, MemVar > {}; - - /** - Base (unimplemented) MethodTo interface. - - Acts as a proxy for MethodToInCa, MethodToGetter and - MethodToSetter (or their const cousins if T is - const-qualified). Tag must be one of (InCa, InCaVoid, - Getter, Setter). The other args are as documented for the - aforementioned proxied types. - - See MethodToInCa for more information about the parameters. - */ - template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< MethodSignature >::Value> - struct MethodTo DOXYGEN_FWD_DECL_KLUDGE; - - //! Behaves like MethodToInCa. For const methods, const-qualify T. - template ::FunctionType Func, bool UnlockV8> - struct MethodTo< InCa, T, Sig, Func, UnlockV8 > : MethodToInCa - {}; - - //! Behaves like MethodToInCaVoid. For const methods, const-qualify T. - template ::FunctionType Func, bool UnlockV8> - struct MethodTo< InCaVoid, T, Sig, Func, UnlockV8 > : MethodToInCaVoid - {}; - - //! Behaves like MethodToGetter. For const methods, const-qualify T. - template ::FunctionType Func, bool UnlockV8> - struct MethodTo< Getter, T, Sig, Func, UnlockV8 > : MethodToGetter - {}; - - //! Behaves like MethodToSetter. For const methods, const-qualify T. - template ::FunctionType Func, bool UnlockV8> - struct MethodTo< Setter, T, Sig, Func, UnlockV8 > : MethodToSetter - {}; - - /** - Base (unimplemented) FunctorTo interface. - - Behaves like one of the following, depending on the Tag type: - - FunctorToInCa (Tag=InCa), FunctorToInCaVoid (Tag=InCaVoid), - FunctorToGetter (Tag=Getter), FunctorToSetter (Tag=Setter) - - See FunctorToInCa for more information about the parameters. - */ - template >::Value - > - struct FunctorTo DOXYGEN_FWD_DECL_KLUDGE; - - //! Behaves like FunctorToInCa. - template - struct FunctorTo< InCa, FtorT, Sig, UnlockV8 > : FunctorToInCa - {}; - - //! Behaves like FunctorToInCaVoid. - template - struct FunctorTo< InCaVoid, FtorT, Sig, UnlockV8 > : FunctorToInCaVoid - {}; - - //! Behaves like FunctorToGetter. - template - struct FunctorTo< Getter, FtorT, Sig, UnlockV8 > : FunctorToGetter - {}; - - //! Behaves like FunctorToSetter. - template - struct FunctorTo< Setter, FtorT, Sig, UnlockV8 > : FunctorToSetter - {}; -} -/** LICENSE - - This software's source code, including accompanying documentation and - demonstration applications, are licensed under the following - conditions... - - The author (Stephan G. Beal [http://wanderinghorse.net/home/stephan/]) - explicitly disclaims copyright in all jurisdictions which recognize - such a disclaimer. In such jurisdictions, this software is released - into the Public Domain. - - In jurisdictions which do not recognize Public Domain property - (e.g. Germany as of 2011), this software is Copyright (c) 2011 - by Stephan G. Beal, and is released under the terms of the MIT License - (see below). - - In jurisdictions which recognize Public Domain property, the user of - this software may choose to accept it either as 1) Public Domain, 2) - under the conditions of the MIT License (see below), or 3) under the - terms of dual Public Domain/MIT License conditions described here, as - they choose. - - The MIT License is about as close to Public Domain as a license can - get, and is described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - - The full text of the MIT License follows: - - -- - Copyright (c) 2011 Stephan G. Beal (http://wanderinghorse.net/home/stephan/) - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - --END OF MIT LICENSE-- - - For purposes of the above license, the term "Software" includes - documentation and demonstration source code which accompanies - this software. ("Accompanies" = is contained in the Software's - primary public source code repository.) - -*/ - -#endif /* CVV8_TO_X_HPP_INCLUDED */ diff --git a/vendor/libv8-convert/cvv8/arguments.hpp b/vendor/libv8-convert/cvv8/arguments.hpp deleted file mode 100644 index 307db2cae..000000000 --- a/vendor/libv8-convert/cvv8/arguments.hpp +++ /dev/null @@ -1,817 +0,0 @@ -#if !defined(V8_CONVERT_ARGUMENTS_HPP_INCLUDED) -#define V8_CONVERT_ARGUMENTS_HPP_INCLUDED -#include "convert.hpp" -#include - -namespace cvv8 { - - /** - A functor which fetches an argument by index. - - I = the argument index to fetch. - - The class is intended mainly to be invoked via code paths - selected by template metaprograms, thus the hard-coding of - the argument parameter index at compile-time. - */ - template - struct ArgAt - { - typedef char AssertIndex[ (I>=0) ? 1 : -1]; - /** - Returns argv[I] if argv.Length() is <= I, else v8::Undefined() - is returned. - */ - inline v8::Handle operator()( v8::Arguments const & argv ) const - { - return (argv.Length() > I) ? argv[I] : v8::Undefined(); - } - }; - - /** - Functor to fetch an argument and return its result - as a native value. - - I = the argument index to fetch. - - T = the native type to convert to. CastFromJS() must be legal. - */ - template - struct ArgAtCast - { - typedef JSToNative J2N; - typedef typename J2N::ReturnType ReturnType; - typedef char AssertIndex[ (I>=0) ? 1 : -1]; - /** - Returns CastFromJS( ArtAt(argv) ). - */ - inline ReturnType operator()( v8::Arguments const & argv ) const - { - typedef ArgAt Proxy; - return CastFromJS( Proxy()(argv) ); - } - }; - - /** - Marker class, for documentation purposes. - */ - struct ValuePredicate - { - /** - Must evaluate the handle and return true or false. - The framework cannot guaranty that h.IsEmpty() is false, - so implementations should be in the habit of checking it. - */ - bool operator()( v8::Handle const & h ) const; - }; - - /** - A functor interface for determining if a JS value - "is-a" value of a particular native type. The default - implementation is useable for any type for which the - following is legal: - - @code - T const * t = CastFromJS( aV8Handle ); - @endcode - - Specializations are used for most data types, but this - one is fine for client-bound types conformant with - CastFromJS(). - - Note that the default specializations treat T as a plain type, - discarding const/pointer/reference qualifiers. Certain types may - require that ValIs (and similar) be specialized in order - to behave properly. - */ - template - struct ValIs : ValuePredicate - { - typedef T Type; - /** - Returns true if v appears to contain a (T*). - */ - inline bool operator()( v8::Handle const & v ) const - { - return NULL != CastFromJS(v); - } - }; - - //! Specialization to treat (T const) as T. - template struct ValIs : ValIs {}; - //! Specialization to treat (T const &) as T. - template struct ValIs : ValIs {}; - //! Specialization to treat (T *) as T. - template struct ValIs : ValIs {}; - //! Specialization to treat (T const *) as T. - template struct ValIs : ValIs {}; - - /** - Specialization which treats void as the v8::Undefined() value. - */ - template <> - struct ValIs - { - typedef void Type; - /** - Returns true only if h is not empty and h->IsUndefined(). Note - that an empty handle evaluates to false in this context because - Undefined is a legal value whereas an empty handle is not. - (Though Undefined might not be _semantically_ legal in any given - use case, it is legal to dereference such a handle.) - */ - inline bool operator()( v8::Handle const & h ) const - { - return h.IsEmpty() ? false : h->IsUndefined(); - } - }; - -#if !defined(DOXYGEN) - namespace Detail { - /** - ValuePredicate impl which returns retrue if - Getter returns true for the given value. - - Getter must be a pointer to one of the v8::Value::IsXXX() - functions. This functor returns true if the passed-in handle is - not empty and its IsXXX() function returns true. - */ - template - struct ValIs_X : ValuePredicate - { - inline bool operator()( v8::Handle const & v ) const - { - return v.IsEmpty() ? false : ((*v)->*Getter)(); - } - }; - - /** - A ValuePredicate impl which returns true only if - the given handle is-a number and the number is in the - inclusive range (std::numeric_limits::min .. - max()). - */ - template - struct ValIs_NumberStrictRange : ValuePredicate - { - typedef NumT Type; - inline bool operator()( v8::Handle const & h ) const - { - if( h.IsEmpty() || ! h->IsNumber() ) return false; - else - { - double const dv( h->NumberValue() ); - return (dv >= std::numeric_limits::min()) - && (dv <= std::numeric_limits::max()); - } - } - }; - /** Special-case specialization which returns true if the given - handle is-a Number (without checking the range, which is - not necessary for this specific type in this context). - */ - template <> - struct ValIs_NumberStrictRange : ValuePredicate - { - typedef double Type; - inline bool operator()( v8::Handle const & h ) const - { - return !h.IsEmpty() && h->IsNumber(); - } - }; - } -#endif // DOXYGEN - - /** A Value predicate which returns true if its argument is-a Array. */ - struct ValIs_Array : Detail::ValIs_X<&v8::Value::IsArray> {}; - /** A Value predicate which returns true if its argument is-a Object. */ - struct ValIs_Object : Detail::ValIs_X<&v8::Value::IsObject> {}; - /** A Value predicate which returns true if its argument is-a Boolean. */ - struct ValIs_Boolean : Detail::ValIs_X<&v8::Value::IsBoolean> {}; - /** A Value predicate which returns true if its argument is-a Date. */ - struct ValIs_Date : Detail::ValIs_X<&v8::Value::IsDate> {}; - /** A Value predicate which returns true if its argument is-a External. */ - struct ValIs_External : Detail::ValIs_X<&v8::Value::IsExternal> {}; - /** A Value predicate which returns true if its argument has a false value. */ - struct ValIs_False : Detail::ValIs_X<&v8::Value::IsFalse> {}; - /** A Value predicate which returns true if its argument is-a Function. */ - struct ValIs_Function : Detail::ValIs_X<&v8::Value::IsFunction> {}; - /** A Value predicate which returns true if its argument is-a In32. */ - struct ValIs_Int32 : Detail::ValIs_X<&v8::Value::IsInt32> {}; - /** A Value predicate which returns true if its argument is-a UInt32. */ - struct ValIs_UInt32 : Detail::ValIs_X<&v8::Value::IsUint32 /* Note the "UInt" vs "Uint" descrepancy. i consider Uint to be wrong.*/ > {}; - /** A Value predicate which returns true if its argument is Null (JS null, not C++ NULL). */ - struct ValIs_Null : Detail::ValIs_X<&v8::Value::IsNull> {}; - /** A Value predicate which returns true if its argument has the special Undefined value. */ - struct ValIs_Undefined : Detail::ValIs_X<&v8::Value::IsUndefined> {}; - /** A Value predicate which returns true if its argument is-a Number. */ - struct ValIs_Number : Detail::ValIs_X<&v8::Value::IsNumber> {}; - /** A Value predicate which returns true if its argument is-a RegExp. */ - struct ValIs_RegExp : Detail::ValIs_X<&v8::Value::IsRegExp> {}; - /** A Value predicate which returns true if its argument is-a String. */ - struct ValIs_String : Detail::ValIs_X<&v8::Value::IsString> {}; - /** A Value predicate which returns true if its argument has a true value. */ - struct ValIs_True : Detail::ValIs_X<&v8::Value::IsTrue> {}; - - // FIXME: reverse the parent relationships between e.g. ValIs and ValIs_Array. - /** A Value predicate which returns true if its argument is a number capable - of fitting in an int8_t. */ - template <> struct ValIs : Detail::ValIs_NumberStrictRange {}; - /** A Value predicate which returns true if its argument is a number capable - of fitting in an uint8_t. */ - template <> struct ValIs : Detail::ValIs_NumberStrictRange {}; - /** A Value predicate which returns true if its argument is a number capable - of fitting in an int16_t. */ - template <> struct ValIs : Detail::ValIs_NumberStrictRange {}; - /** A Value predicate which returns true if its argument is a number capable - of fitting in an uint16_t. */ - template <> struct ValIs : Detail::ValIs_NumberStrictRange {}; - /** A Value predicate which returns true if its argument is a number capable - of fitting in an int32_t. */ - template <> struct ValIs : Detail::ValIs_NumberStrictRange {}; - /** A Value predicate which returns true if its argument is a number capable - of fitting in an uint32_t. */ - template <> struct ValIs : Detail::ValIs_NumberStrictRange {}; - /** A Value predicate which returns true if its argument is a number capable - of fitting in an int64_t. */ - template <> struct ValIs : Detail::ValIs_NumberStrictRange {}; - /** A Value predicate which returns true if its argument is a number capable - of fitting in an uint64_t. */ - template <> struct ValIs : Detail::ValIs_NumberStrictRange {}; - /** A Value predicate which returns true if its argument is-a Number value. */ - template <> struct ValIs : ValIs_Number {}; - //! Special-case specialization to treat C strings as JS strings. - template <> struct ValIs : ValIs_String {}; - //! Special-case specialization to treat v8 strings as JS strings. - template <> struct ValIs : ValIs_String {}; - //! A Value predicate which returns true if its argument is-a Array. */ - template <> struct ValIs : ValIs_Array {}; - //! A Value predicate which returns true if its argument is-a Object. */ - template <> struct ValIs : ValIs_Object {}; - //! A Value predicate which returns true if its argument is-a Boolean. */ - template <> struct ValIs : ValIs_Boolean {}; - //! A Value predicate which returns true if its argument is-a Date. */ - template <> struct ValIs : ValIs_Date {}; - //! A Value predicate which returns true if its argument is-a External. */ - template <> struct ValIs : ValIs_External {}; - //! A Value predicate which returns true if its argument is-a Function. */ - template <> struct ValIs : ValIs_Function {}; - //! A Value predicate which returns true if its argument is-a Int32. */ - template <> struct ValIs : ValIs_Int32 {}; - //! A Value predicate which returns true if its argument is-a UInt32. */ - template <> struct ValIs : ValIs_UInt32 {}; - //! A Value predicate which returns true if its argument is-a Number. */ - template <> struct ValIs : ValIs_Number {}; - //! A Value predicate which returns true if its argument is-a RegExp. */ - template <> struct ValIs : ValIs_RegExp {}; - //! A Value predicate which returns true if its argument is-a String. */ - template <> struct ValIs : ValIs_String {}; - //! Specialization to treat Handle as T. */ - template struct ValIs< v8::Handle > : ValIs< T > {}; - //! Specialization to treat Local as T. */ - template struct ValIs< v8::Local > : ValIs< T > {}; - //! Specialization to treat Persistent as T. */ - template struct ValIs< v8::Persistent > : ValIs< T > {}; - - /** - Marker class, mainly for documentation purposes. - - Classes matching this concept "evaluate" a v8::Arguments - object for validity without actually performing any - "application logic." These are intended to be used as - functors, primarily triggered via code paths selected by - template metaprograms. - - They must be default-construcable and should have no - private state. Their public API consists of only operator(). - - This Concept's operator() is intended only to be used for - decision-making purposes ("are there enough arguments?" or - "are the arguments of the proper types?"), and not - higher-level application logic. - */ - struct ArgumentsPredicate - { - /** - Must "evaluate" the arguments and return true or false. - */ - bool operator()( v8::Arguments const & ) const; - }; - - /** - Functor to evaluate whether an Arguments list - has a certain range of argument count. - - Min is the minimum number. Max is the maximum. The range is - inclusive. Use (Max - struct Argv_Length : ArgumentsPredicate - { - private: - typedef char AssertMinIsPositive[ (Min_>=0) ? 1 : -1 ]; - enum { Min = Min_, Max = Max_ }; - public: - /** - Returns true if av meets the argument count - requirements defined by the Min and Max - values. - */ - bool operator()( v8::Arguments const & av ) const - { - - int const argc = av.Length(); - return (Max < Min) - ? argc >= Min - : (argc>=Min) && (argc<=Max); - } - }; - - /** - Arguments predicate functor. - - Index = arg index to check. - - ValIsType must match the ValuePredicate interface. - */ - template - struct ArgAt_Is : ArgumentsPredicate - { - /** - Returns true if ValType()( av[Index] ) is true. - */ - inline bool operator()( v8::Arguments const & av ) const - { - return (Index >= av.Length()) - ? false - : ValIsType()( av[Index] ); - } - }; - - /** - Arguments predicate functor. - - Index = arg index to check. - - T is a type for which ValIs is legal. The functor - returns true if ValIs returns true the argument - at the given index. - */ - template - struct ArgAt_IsA : ArgAt_Is< Index, ValIs > {}; - - namespace Detail { - /** - Functor which proxies the v8::Value "is-a" functions. - - Index is the argument index to check. Getter is the - member to be used to perform the is-a evaluation. - */ - template - struct ArgAt_IsX : ArgumentsPredicate - { - /** - Returns true only if (Index < av.Length()) - and av->Getter() returns true. - */ - inline bool operator()( v8::Arguments const & av ) const - { - return ( av.Length() <= Index ) - ? false - : ((*av[Index])->*Getter)(); - } - }; - } - - //! ArgumentsPredicate which returns true if the argument at Index is-a Array. */ - template - struct ArgAt_IsArray : Detail::ArgAt_IsX {}; - - //! ArgumentsPredicate which returns true if the argument at Index is-a Object. */ - template - struct ArgAt_IsObject : Detail::ArgAt_IsX {}; - - //! ArgumentsPredicate which returns true if the argument at Index is-a Boolean. */ - template - struct ArgAt_IsBoolean : Detail::ArgAt_IsX {}; - - //! ArgumentsPredicate which returns true if the argument at Index is-a Date. */ - template - struct ArgAt_IsDate : Detail::ArgAt_IsX {}; - - //! ArgumentsPredicate which returns true if the argument at Index is-a External. */ - template - struct ArgAt_IsExternal : Detail::ArgAt_IsX {}; - - //! ArgumentsPredicate which returns true if the argument at Index has a false value. */ - template - struct ArgAt_IsFalse : Detail::ArgAt_IsX {}; - - //! ArgumentsPredicate which returns true if the argument at Index is-a Function. */ - template - struct ArgAt_IsFunction : Detail::ArgAt_IsX {}; - - //! ArgumentsPredicate which returns true if the argument at Index is-a Int32Boolean. */ - template - struct ArgAt_IsInt32 : Detail::ArgAt_IsX {}; - - //! ArgumentsPredicate which returns true if the argument at Index is-a UInt32. */ - template - struct ArgAt_IsUInt32 : Detail::ArgAt_IsX {}; - - //! ArgumentsPredicate which returns true if the argument at Index has the special Null value. */ - template - struct ArgAt_IsNull : Detail::ArgAt_IsX {}; - - //! ArgumentsPredicate which returns true if the argument at Index has the special Undefined value. */ - template - struct ArgAt_IsUndefined : Detail::ArgAt_IsX {}; - - //! ArgumentsPredicate which returns true if the argument at Index is-a Number. */ - template - struct ArgAt_IsNumber : Detail::ArgAt_IsX {}; - - //! ArgumentsPredicate which returns true if the argument at Index is-a RegExp. */ - template - struct ArgAt_IsRegExp : Detail::ArgAt_IsX {}; - - //! ArgumentsPredicate which returns true if the argument at Index is-a String. */ - template - struct ArgAt_IsString : Detail::ArgAt_IsX {}; - - //! ArgumentsPredicate which returns true if the argument at Index has a True value. */ - template - struct ArgAt_IsTrue : Detail::ArgAt_IsX {}; - - - /** - ArgumentsPredicate functor which always returns true. - - This currently has only one obscure use: as the predicate given to a - PredicatedInCa in conjunction with an N-arity callback, used as a - catch-all fallback as the last item in a list of PredicatedInCas - passed to PredicatedInCaDispatcher. (Got that?) - */ - struct Argv_True : ArgumentsPredicate - { - inline bool operator()( v8::Arguments const & ) const - { - return true; - } - }; - /** ArgumentsPredicate which always returns false. - - This predicate has only one known, rather obscure use in combination - with type lists. - */ - struct Argv_False : ArgumentsPredicate - { - inline bool operator()( v8::Arguments const & ) const - { - return false; - } - }; - - /** - An ArgumentsPredicate implementation which takes - two ArgumentsPredicate functors as template parameters - and combines them using an AND operation. - - See Argv_AndN if you just want to combine more than two functors. - (Argv_AndN can also be used for two functors but is more verbose - than this form for that case.) - */ - template - struct Argv_And : ArgumentsPredicate - { - /** - Returns true only if ArgPred1()(args) and - ArgPred2()(args) both return true. - */ - inline bool operator()( v8::Arguments const & args ) const - { - return ArgPred1()( args ) && ArgPred2()( args ); - } - }; - - /** - The "or" equivalent of Argv_And. - - Use Argv_OrN for chaining more than two predicates. - */ - template - struct Argv_Or : ArgumentsPredicate - { - /** - Returns true only if one of ArgPred1()(args) or - ArgPred2()(args) return true. - */ - inline bool operator()( v8::Arguments const & args ) const - { - return ArgPred1()( args ) || ArgPred2()( args ); - } - }; - - /** - This ArgumentsPredicate implementation combines a list of - other ArgumentsPredicates using an AND operation on the combined - results of each functor. - - PredList must be a type-list containing ArgumentsPredicate types. - This functor is a predicate which performs an AND operation on all - of the predicates in the type list. - - Note that an empty typelist evaluates to True in this context, for - deeply arcane reasons. - - See Argv_And if you just want to combine two functors - (it is more succinct for that case). - - Example: - - @code - // Predicate matching (function, ANYTHING, function) signature: - typedef Argv_AndN< CVV8_TYPELIST(( - Argv_Length<3>, - ArgAt_IsFunction<0>, - ArgAt_IsFunction<2> - )) > PredFuncXFunc; - @endcode - */ - template - struct Argv_AndN : ArgumentsPredicate - { - /** - Returns true only if all predicates in PredList - return true when passed the args object. - */ - inline bool operator()( v8::Arguments const & args ) const - { - typedef typename PredList::Head Head; - typedef typename tmp::IfElse< tmp::SameType::Value, - Argv_True, - Head>::Type P1; - typedef typename PredList::Tail Tail; - typedef Argv_AndN P2; - return P1()( args ) && P2()(args); - } - }; - - //! End-of-list specialization. - template <> - struct Argv_AndN : Argv_True {}; - - /** - The "or" equivalent of Argv_AndN. - - When chaining only two predicates Argv_Or offers - a more succinct equivalent to this type. - - Note that an empty typelist evaluates to False in this context, for - deeply arcane reasons. - */ - template - struct Argv_OrN : ArgumentsPredicate - { - /** - Returns true only if one of the predicates in PredList - returns true when passed the args object. - */ - inline bool operator()( v8::Arguments const & args ) const - { - typedef typename PredList::Head P1; - typedef typename PredList::Tail Tail; - typedef Argv_OrN P2; - return P1()( args ) || P2()(args); - } - }; - - //! End-of-list specialization. - template <> - struct Argv_OrN : ArgumentsPredicate - { - /** - Always returns false. - */ - inline bool operator()( v8::Arguments const & ) const - { - return false; - } - }; - - /** - Intended as a base class for a couple other - PredicatedXyz types. - - This type combines ArgumentsPredicate ArgPred and - CallT::Call() into one type, for template-based dispatching - purposes. - - ArgPred must be-a ArgumentsPredicate. CallT must - be a type having a static Call() function taking one - (v8::Arguments const &) and returning any type. - - This type uses subclassing instead of composition - to avoid having to specify the CallT::Call() return - type as an additional template parameter. i don't seem to - be able to template-calculate it from here. We can't use - CallT::ReturnType because for most bindings that value - is different from its Call() return type. We will possibly - eventually run into a problem with the lack of a way - to get Call()'s return type. - - @see PredicatedInCaDispatcher - */ - template - struct PredicatedInCaLike : ArgPred, CallT {}; - - /** - PredicatedInCa combines an ArgumentsPredicate functor - (ArgPred) with an InCa type, such that we can create lists - of functor/callback pairs for use in dispatching callbacks - based on the results of ArgumentPredicates. - - InCaT must implement the InCa interface. - - This type is primarily intended to be used together with - PredicatedInCaDispatcher. - - @see PredicatedInCaLike - - Reminder to self: this class is only in arguments.hpp, as opposed to - invocable_core.hpp, because i want (for pedantic - documentation-related reasons) this class to inherit - ArgumentsPredicate, which invocable*.hpp does not know about. - We might want to move ArgumentsPredicate and - ValuePredicate into convert_core.hpp and move this class back - into invocable_core.hpp. - - @see PredicatedInCaDispatcher - */ - template - struct PredicatedInCa : PredicatedInCaLike {}; - - /** - This class creates an InvocationCallback which dispatches to one of an - arbitrarily large set of other InvocationCallbacks, as determined by - predicate rules. - - PredList must be a type-list (e.g. Signature) of PredicatedInCa - implementations. See Call() for more details. - - Basic example: - - @code - // Overloads for 1-3 arguments: - typedef PredicatedInCa< Argv_Length<1>, ToInCa<...> > Cb1; - typedef PredicatedInCa< Argv_Length<2>, ToInCa<...> > Cb2; - typedef PredicatedInCa< Argv_Length<3>, ToInCa<...> > Cb3; - // Fallback impl for 0 or 4+ args: - typedef PredicatedInCa< Argv_True, InCaToInCa > CbN; - // Side note: this ^^^^^^^^^^^^^^ is the only known use for the - // Argv_True predicate. - - // Combine them into one InvocationCallback: - typedef PredicatedInCaDispatcher< CVV8_TYPELIST(( - Cb1, Cb2, Cb3, CbN - ))> AllOverloads; - v8::InvocationCallback cb = AllOverloads::Call; - @endcode - */ - template - struct PredicatedInCaDispatcher - : InCa - { - /** - For each PredicatedInCa (P) in PredList, if P()(argv) - returns true then P::Call(argv) is returned, else the next - predicate in the list is tried. - - If no predicates match then a JS-side exception will be triggered. - */ - static inline v8::Handle Call( v8::Arguments const & argv ) - { - typedef typename PredList::Head Head; - typedef typename tmp::IfElse< tmp::SameType::Value, - Argv_False, - Head>::Type Ftor; - typedef typename PredList::Tail Tail; - typedef char AssertEndOfListCheck[ tmp::SameType::Value - ? (tmp::SameType::Value ? 1 : -1) - : 1 - /* ensures that the Argv_False kludge does not call - any specialization other than the NilType one. - */ - ]; - return ( Ftor()( argv ) ) - ? Detail::OverloadCallHelper::Call( argv ) - : PredicatedInCaDispatcher::Call(argv); - } - }; - - //! End-of-list specialization. - template <> - struct PredicatedInCaDispatcher< tmp::NilType > : InCa - { - /** - Triggers a JS-side exception explaining (in English text) that no - overloads could be matched to the given arguments. - */ - static inline v8::Handle Call( v8::Arguments const & argv ) - { - return Toss(StringBuffer()<<"No predicates in the " - << "argument dispatcher matched the given " - << "arguments (arg count="< - struct PredicatedCtorForwarder - : PredicatedInCaLike {}; - - /** - The constructor counterpart of PredicatedInCaDispatcher. - PredList must be a typelist of PredicatedCtorForwarder (or - interface-compatible) types. The ReturnType part of the - typelist must be the base type the constructors in the list - can return (they must all share a common base). Clients must - not pass the ContextT parameter - it is required internally - for handling the end-of-typelist case. - - This template instantiates TypeName, so - if that template is to be specialized by client code, it should - be specialized before this template used. - */ - template - struct PredicatedCtorDispatcher - { - /** - Force the ContextT into a native handle type. - */ - typedef typename TypeInfo::NativeHandle ReturnType; - /** - For each PredicatedCtorForwarder (P) in PredList, if P()(argv) - returns true then P::Call(argv) is returned, else the next - predicate in the list is tried. - - If no predicates match then a JS-side exception will be triggered. - */ - static ReturnType Call( v8::Arguments const & argv ) - { - typedef typename PredList::Head Head; - typedef typename tmp::IfElse< tmp::SameType::Value, - Argv_False, - Head>::Type Ftor; - typedef typename PredList::Tail Tail; - return ( Ftor()( argv ) ) - ? Detail::CtorFwdDispatch::Call( argv ) - : PredicatedCtorDispatcher::Call(argv); - } - }; - - //! End-of-list specialization. - template - struct PredicatedCtorDispatcher< tmp::NilType, ContextT > : Signature< ContextT * () > - { - typedef typename TypeInfo::NativeHandle ReturnType; - /** - Triggers a native exception explaining (in English text) that no - overloads could be matched to the given arguments. It's kinda - cryptic, but we can't be more specific at this level of - the API. - */ - static ReturnType Call( v8::Arguments const & argv ) - { - StringBuffer os; - os << "No predicates in the " - << TypeName::Value - << " ctor argument dispatcher matched the given " - << "arguments (arg count="< // arg! Requires C++0x! -#include -#include // hope the client's platform is recent! -#include -#include -#include -#include -#include -#include -#include - -#if !defined(CVV8_CONFIG_HAS_LONG_LONG) -/* long long in C++ requires C++0x or compiler extensions. */ -# define CVV8_CONFIG_HAS_LONG_LONG 0 -#endif - -#include "signature_core.hpp" /* only needed for the Signature used by the generated code. */ -#include "tmp.hpp" - -namespace cvv8 { - - - /** - A convenience base type for TypeInfo specializations. - */ - template - struct TypeInfoBase - { - /** - The unqualified type T. In some special cases, Type _may_ - differ from T. - */ - typedef T Type; - /** - The "handle" type used to pass around native objects - between the JS and Native worlds. - - In _theory_ we can also use shared/smart pointers with - this typedef, but that requires custom handling in other - template code (mainly because we cannot store a - full-fledged shared pointer object directly inside a JS - object). - */ - typedef NHT NativeHandle; - - // MAYBE to do: add a function to get a pointer to the object, e.g. - // for dereferencing smart pointers. So far it's not been necessary. - // static NativeHandle Pointer( NativeHandle x ) { return x; } - }; - - /** - This may optionally be specialized for client-defined types - to define the type name used by some error reporting - code. - - The default implementation is usable but not all that useful. - */ - template - struct TypeName - { - /** Specializations must have a non-NULL value, and any number - of specializations may legally have the same value. - */ - static char const * Value; - }; -#if 0 - /** - This default implementation is unfortunate, but quite a bit - of error-reporting code uses this, with the assumption that - if it was worth binding to JS then it's worth having a - useful type name in error strings. - - FIXME: remove the default specialization if we can, as it will - cause us problems with some planned/potential uses which cross - DLL boundaries (there may be multiple definitions with different - addresses). - */ - template - char const * TypeName::Value = "T"; -#endif - - /** @def CVV8_TypeName_DECL - - A convenience macro for declaring a TypeName specialization. X must - be a type name with extra wrapping parenthesis, e.g.: - - @code - CVV8_TypeName_DECL((MyType)); - @endcode - - They are required so that we can also support template types with commas - in the names, e.g. (std::map). - - It must be called from inside the cvv8 namespace. - */ -#define CVV8_TypeName_DECL(X) template <> struct TypeName< cvv8::sl::At<0,CVV8_TYPELIST(X) >::Type > \ - { const static char * Value; } - - /** @def CVV8_TypeName_IMPL - - The counterpart of CVV8_TypeName_DECL, this must be called from the - cvv8 namespace. The X argument is as documented for CVV8_TypeName_DECL - and the NAME argument must be a C string. - - Example: - - @code - CVV8_TypeName_IMPL((MyType),"MyType"); - @endcode - */ -#define CVV8_TypeName_IMPL(X,NAME) char const * TypeName< cvv8::sl::At<0,CVV8_TYPELIST(X) >::Type >::Value = NAME - /** @def CVV8_TypeName_IMPL2 - - Almost identical to CVV8_TypeName_IMPL(), but can be used without - having first explicitly specializing TypeName. - */ -#define CVV8_TypeName_IMPL2(X,NAME) template <> CVV8_TypeName_IMPL(X,NAME) - - -#if 1 - template - struct TypeName : TypeName {}; - template - struct TypeName : TypeName {}; - template - struct TypeName : TypeName {}; -#endif - - /** - Describes basic type information regarding a type, for purposes - of static typing during JS-to/from-Native conversions. - - The default instantiation is suitable for most - cases. Specializations may be required in certain JS/Native - binding cases. - */ - template - struct TypeInfo : TypeInfoBase - { - }; - - template - struct TypeInfo : TypeInfo {}; - - template - struct TypeInfo : TypeInfo {}; - - template - struct TypeInfo : TypeInfo {}; - - template - struct TypeInfo : TypeInfo {}; - - template - struct TypeInfo : TypeInfo {}; - -#if 1 // this will only theoretically do what i want. Never actually tried to use a non-pointer NativeHandle type... - template - struct TypeInfo< v8::Handle > - { - typedef v8::Handle Type; - typedef v8::Handle NativeHandle; - }; -#endif - - /** - Base instantiation for T-to-v8::Handle conversion functor. - Must be specialized or it will not compile. - */ - template - struct NativeToJS - { - /** - Must be specialized. The argument type may be pointer-qualified. - Implementations for non-pod types are encouraged to have two - overloads, one taking (NT const &) and one taking (NT const *), - as this gives the underlying CastToJS() calls more leeway. - **/ - template - v8::Handle operator()( X const & ) const; - private: - typedef tmp::Assertion NativeToJSMustBeSpecialized; - }; - - /** - Specialization to treat (NT*) as (NT). - - NativeToJS must have an operator() taking - (NT const *). - */ - template - struct NativeToJS : NativeToJS -#if 1 - {}; -#else - { - v8::Handle operator()( NT const * v ) const - { - typedef NativeToJS Proxy; - if( v ) return Proxy()(v); - else return v8::Null() - ; - } - }; -#endif - /** - Specialization to treat (NT const *) as (NT). - */ - template - struct NativeToJS : NativeToJS {}; - // { - // typedef typename TypeInfo::Type const * ArgType; - // v8::Handle operator()( ArgType n ) const - // { - // typedef NativeToJS Proxy; - // return Proxy()( n ); - // } - // }; - - /** - Specialization to treat (NT const &) as (NT). - */ - template - struct NativeToJS : NativeToJS {}; - template - struct NativeToJS : NativeToJS {}; - -#if 0 - /** - Specialization to treat (NT &) as (NT). - */ - template - struct NativeToJS : NativeToJS {}; -#else - /** - A specialization to convert from (T&) to JS. - - Be very careful with this, and make sure that - NativeToJS has its own specialization, - as this implementation uses that one as its - basis. - */ - template - struct NativeToJS - { - typedef typename TypeInfo::Type & ArgType; - v8::Handle operator()( ArgType n ) const - { - typedef NativeToJS< typename TypeInfo::NativeHandle > Cast; - return Cast()( &n ); - } - }; -#endif - -#if 0 - template <> - struct NativeToJS - { - /** - Returns v8::Undefined(). - */ - template - v8::Handle operator()(Ignored const &) const - { - return ::v8::Undefined(); - } - }; -#endif - -#if !defined(DOXYGEN) - namespace Detail { - /** - Base implementation for "small" integer conversions (<=32 - bits). - */ - template - struct NativeToJS_int_small - { - v8::Handle operator()( IntegerT v ) const - { - return v8::Integer::New( static_cast(v) ); - } - }; - /** - Base implementation for "small" unsigned integer conversions - (<=32 bits). - */ - template - struct NativeToJS_uint_small - { - v8::Handle operator()( IntegerT v ) const - { - return v8::Integer::NewFromUnsigned( static_cast(v) ); - } - }; - } -#endif // if !defined(DOXYGEN) - - template <> - struct NativeToJS : Detail::NativeToJS_int_small {}; - - template <> - struct NativeToJS : Detail::NativeToJS_uint_small {}; - - template <> - struct NativeToJS : Detail::NativeToJS_int_small {}; - - template <> - struct NativeToJS : Detail::NativeToJS_uint_small {}; - -#if !defined(DOXYGEN) - namespace Detail { - /** - Base implementation for "big" numeric conversions (>32 bits). - */ - template - struct NativeToJS_int_big - { - /** Returns v as a double value. */ - v8::Handle operator()( IntegerT v ) const - { - return v8::Number::New( static_cast(v) ); - } - }; - } -#endif // if !defined(DOXYGEN) - - template <> - struct NativeToJS : Detail::NativeToJS_int_big {}; - - template <> - struct NativeToJS : Detail::NativeToJS_int_big {}; - - template <> - struct NativeToJS - { - v8::Handle operator()( double v ) const - { - return v8::Number::New( v ); - } - }; - - template <> - struct NativeToJS - { - v8::Handle operator()( bool v ) const - { - return v8::Boolean::New( v ); - } - }; - - template - struct NativeToJS< ::v8::Handle > - { - typedef ::v8::Handle handle_type; - v8::Handle operator()( handle_type const & li ) const - { - return li; - } - }; - - template - struct NativeToJS< ::v8::Local > - { - typedef ::v8::Local handle_type; - v8::Handle operator()( handle_type const & li ) const - { - return li; - } - }; - - template - struct NativeToJS< ::v8::Persistent > - { - typedef ::v8::Persistent handle_type; - v8::Handle operator()( handle_type const & li ) const - { - return li; - } - }; - - template <> - struct NativeToJS< ::v8::InvocationCallback > - { - v8::Handle operator()( ::v8::InvocationCallback const f ) const - { - return ::v8::FunctionTemplate::New(f)->GetFunction(); - } - }; - - - template <> - struct NativeToJS - { - v8::Handle operator()( std::string const & v ) const - { - /** This use of v.data() instead of v.c_str() is highly arguable. */ - char const * const cstr = v.data(); - return cstr ? v8::String::New( cstr, static_cast( v.size() ) ) : v8::String::New("",0); - } - }; - - template <> - struct NativeToJS - { - v8::Handle operator()( char const * v ) const - { - if( ! v ) return v8::Null(); - else return v8::String::New( v ); - } - }; - - /** - "Casts" v to a JS value using NativeToJS. - */ - template - inline v8::Handle CastToJS( T const & v ) - { - typedef NativeToJS F; - return F()( v ); - } - - /** - Overload to avoid ambiguity in certain calls. - */ - static inline v8::Handle CastToJS( char const * v ) - { - typedef NativeToJS F; - return F()( v ); - } - - /** - Overload to avoid mis-selection of templates. - */ - static inline v8::Handle CastToJS( v8::InvocationCallback v ) - { - typedef NativeToJS F; - return F()( v ); - } - - /** - Overload to avoid ambiguity in certain calls. - */ - static inline v8::Handle CastToJS( char * v ) - { - typedef NativeToJS F; - return F()( v ); - } - - /** Convenience instance of NativeToJS. */ - static const NativeToJS Int16ToJS = NativeToJS(); - /** Convenience instance of NativeToJS. */ - static const NativeToJS UInt16ToJS = NativeToJS(); - /** Convenience instance of NativeToJS. */ - static const NativeToJS Int32ToJS = NativeToJS(); - /** Convenience instance of NativeToJS. */ - static const NativeToJS UInt32ToJS = NativeToJS(); - /** Convenience instance of NativeToJS. */ - static const NativeToJS Int64ToJS = NativeToJS(); - /** Convenience instance of NativeToJS. */ - static const NativeToJS UInt64ToJS = NativeToJS(); - /** Convenience instance of NativeToJS. */ - static const NativeToJS DoubleToJS = NativeToJS(); - /** Convenience instance of NativeToJS. */ - static const NativeToJS BoolToJS = NativeToJS(); - /** Convenience instance of NativeToJS. */ - static const NativeToJS StdStringToJS = NativeToJS(); - - /** - Converts a native std::exception to a JS exception and throws - that exception via v8::ThrowException(). - */ - template <> - struct NativeToJS - { - /** Returns v8::Exception::Error(ex.what()). - - ACHTUNG: on 20110717 this function was changed to NOT trigger a - JS exception. Prior versions triggered a JS exception, but that - was done due to a misunderstanding on my part (i didn't know v8 - provided a way to create Error objects without throwing). This - change is semantically incompatible with older code which uses - this conversion. - - OLD way of doing it (don't do this!): - - @code - catch( std::exception const & ex ) { return CastToJS(ex); } - @endcode - - The equivalent is now: - - @code - catch( std::exception const & ex ) { return Toss(CastToJS(ex)); } - @endcode - */ - v8::Handle operator()( std::exception const & ex ) const - { - char const * msg = ex.what(); - return v8::Exception::Error(v8::String::New( msg ? msg : "unspecified std::exception" )); - /** ^^^ String::New() internally calls strlen(), which hates it when string==0. */ - } - }; - template <> - struct NativeToJS : NativeToJS {}; - template <> - struct NativeToJS : NativeToJS {}; - template <> - struct NativeToJS : NativeToJS {}; - - - /** - Base interface for converting from native objects to JS - objects. There is no default implementation, and it must be - specialized to be useful. - - When creating custom implementations, remember that in - practice, all custom client-bound types are passed around - internally by non-const pointer. This is in contrast to - conversions of POD- and POD-like types (numbers and strings), - which are passed around by value. - - It is theoretically possible to use smart pointers (with value - semantics) via this API, but it is untested. - */ - template - struct JSToNative - { - typedef typename TypeInfo::NativeHandle ResultType; - //! Must be specialized to be useful. - ResultType operator()( v8::Handle const & h ) const; - }; - - /** Specialization to treat (JST*) as JST. */ - template - struct JSToNative : JSToNative {}; - - /** Specialization to treat (JST*) as JST. */ - template - struct JSToNative : JSToNative {}; - - /** Specialization to treat (JST const *) as (JST *). */ - template - struct JSToNative : JSToNative {}; - - /** - A specialization to convert from JS to (T&). - */ - template - struct JSToNative - { - /** - Uses JSTNative() to try to convert a JS object to a - pointer, and then dereferences that pointer to form - (T&). Beware, however, that this operation throws a native - exeception (deriving from std::exception) if it fails, - because the only other other option is has is to - dereference null and crash your app. - */ - typedef typename TypeInfo::Type & ResultType; - ResultType operator()( v8::Handle const & h ) const - { - typedef JSToNative Cast; - typedef typename Cast::ResultType NH; - NH n = Cast()( h ); - if( ! n ) - { - throw std::runtime_error("JSToNative could not get native pointer. Throwing to avoid dereferencing null!"); - } - else return *n; - } - }; - - /** Specialization to treat (JST const &) as (JST). */ - template - struct JSToNative - { - typedef typename TypeInfo::Type const & ResultType; - ResultType operator()( v8::Handle const & h ) const - { - typedef JSToNative Cast; - typedef typename Cast::ResultType NH; -#if 0 - NH n = Cast()( h ); - if( ! n ) - { - throw std::runtime_error("JSToNative could not get native pointer. Throwing to avoid dereferencing null!"); - } - else return *n; -#else - return Cast()(h); -#endif - } - }; - - - - /** Specialization which passes on v8 Handles as-is. */ - template - struct JSToNative > - { - typedef v8::Handle ResultType; - ResultType operator()( v8::Handle const & h ) const - { - return h; - } - }; - template - struct JSToNative const &> : JSToNative< v8::Handle > {}; - template - struct JSToNative &> : JSToNative< v8::Handle > {}; - - /** Specialization which passes on v8 local Handles as-is. */ - template - struct JSToNative > - { - typedef v8::Local ResultType; - ResultType operator()( v8::Local const & h ) const - { - return h; - } - }; - template - struct JSToNative const &> : JSToNative< v8::Local > {}; - template - struct JSToNative &> : JSToNative< v8::Local > {}; - -#if !defined(DOXYGEN) - namespace Detail - { - template - struct JSToNative_V8Type - { - /** - If h is not empty and is of the correct type - then its converted handle is returned, else - an empty handle is returned. - */ - typedef v8::Handle ResultType; - ResultType operator()( v8::Handle const & h ) const - { - return (h.IsEmpty() || !((*h)->*IsA)()/*man, what a construct!*/) - ? v8::Handle() - : v8::Handle(V8Type::Cast(*h)); - } - }; - } -#endif - template <> - struct JSToNative > : Detail::JSToNative_V8Type< v8::Object, &v8::Value::IsObject> - {}; - template <> - struct JSToNative< v8::Handle &> : JSToNative< v8::Handle > {}; - template <> - struct JSToNative< v8::Handle const &> : JSToNative< v8::Handle > {}; - - - template <> - struct JSToNative > : Detail::JSToNative_V8Type< v8::Array, &v8::Value::IsArray> - {}; - template <> - struct JSToNative< v8::Handle &> : JSToNative< v8::Handle > {}; - template <> - struct JSToNative< v8::Handle const &> : JSToNative< v8::Handle > {}; - - template <> - struct JSToNative > : Detail::JSToNative_V8Type< v8::Function, &v8::Value::IsFunction> - {}; - template <> - struct JSToNative< v8::Handle &> : JSToNative< v8::Handle > {}; - template <> - struct JSToNative< v8::Handle const &> : JSToNative< v8::Handle > {}; - - /** - An X-to-void specialization which we cannot use in the generic - case due to the syntactic limitations of void. - */ - template <> - struct JSToNative - { - typedef void ResultType; - ResultType operator()( ... ) const - { - return; - } - }; - - /** - A very arguable specialization which tries to convert a JS - value to native (void*) via v8::External. - */ - template <> - struct JSToNative - { - typedef void * ResultType; - /** - If h is-a External then this return its value, else it - return 0. - - We could arguably check if it is an object and has - internal fields, and return the first one, but i think - that would be going too far considering how arguably the - v8-to-(void *) conversion is in the first place. - */ - ResultType operator()( v8::Handle const & h ) const - { - if( h.IsEmpty() || ! h->IsExternal() ) return 0; - return v8::External::Cast(*h)->Value(); - } - }; - /** - A very arguable specialization which tries to convert a JS - value to native (void*) via v8::External. - */ - template <> - struct JSToNative - { - typedef void const * ResultType; - /** - If h is-a External then this return its value, else it - return 0. - - We could arguably check if it is an object and has - internal fields, and return the first one, but i think - that would be going to far considering how arguably the - v8-to-(void *) conversion is in the first place. - */ - ResultType operator()( v8::Handle const & h ) const - { - if( h.IsEmpty() || ! h->IsExternal() ) return 0; - return v8::External::Cast(*h)->Value(); - } - }; - - /** - A concrete JSToNative implementation intended to be used as the - base class for JSToNative implementations where T is "bound - to JS" in JS objects, and those JS objects meet the following - requirements: - - - They have exactly InternalFieldCount internal fields. - - - They have a C/C++-native object of type (T*) (or convertible - to type (T*)) stored as a v8::External value in the JS-object - internal field number InternalFieldIndex. - - Note that the InternalFieldCount check is only a quick - sanity-checking mechanism, and is by far not foolproof because - the majority of JS-bound native types only use 1 internal - field. - - It is illegal for InternalFieldCount to be equal to or smaller - than InternalFieldIndex, or for either value to be - negative. Violating these invariants results in a compile-time - assertion. - - If an object to convert matches the field specification but - is not a T (or publically derived from T) then results are - undefined (this could lead to a crash at runtime). - - There are cases where very-misbehaving JS code can force this - particular conversion algorithm to mis-cast the native. While - they have never been seen "in the wild", they can - theoretically happen. If that bothers you, and you want to be - able to sleep soundly at night, use - JSToNative_ObjectWithInternalFieldsTypeSafe instead of this - class. - - @see JSToNative_ObjectWithInternalFieldsTypeSafe - - */ - template - struct JSToNative_ObjectWithInternalFields - { - private: - typedef char AssertIndexRanges - [tmp::Assertion< - (InternalFieldIndex>=0) - && (InternalFieldCount>0) - && (InternalFieldIndex < InternalFieldCount) - >::Value - ? 1 : -1]; - public: - typedef typename TypeInfo::NativeHandle ResultType; - /** - If h is-a Object and it meets the requirements described - in this class' documentation, then this function returns - the result of static_cast(void*), using the (void*) - extracted from the Object. If the requirements are not met - then NULL is returned. - - See the class docs for more details on the requirements - of the passed-in handle. - - If SearchPrototypeChain is true and this object does not - contain a native then the prototype chain is searched. - This is generally only required when bound types are - subclassed. - */ - ResultType operator()( v8::Handle const & h ) const - { - if( h.IsEmpty() || ! h->IsObject() ) return NULL; - else - { - void * ext = NULL; - v8::Handle proto(h); - while( !ext && !proto.IsEmpty() && proto->IsObject() ) - { - v8::Local const & obj( v8::Object::Cast( *proto ) ); - ext = (obj->InternalFieldCount() != InternalFieldCount) - ? NULL - : obj->GetPointerFromInternalField( InternalFieldIndex ); - if( ! ext ) - { - if( !SearchPrototypeChain ) break; - else proto = obj->GetPrototype(); - } - } - return ext ? static_cast(ext) : NULL; - } - } - }; - - /** - A concrete JSToNative implementation (to be used as a base class) - which does a type-safe conversion from JS to (T*). - - T is the bound native type. A pointer of this type is expected - in the object-internal field specified by ObjectFieldIndex. - - Each value to be converted is checked for an internal field - (of type v8::External) at the index specified by - TypeIdFieldIndex. If (and only if) that field contains a - v8::External which holds the value TypeID is the conversion - considered legal. If they match but the native value stored - in field ObjectFieldIndex is NOT-a-T then results are - undefined. Note that the TypeID value is compared by pointer - address, not by its byte contents (which may legally be - NULL). - - If SearchPrototypeChain is true and the passed-in object - contains no native T then the prototype chain is checked - recursively. This is normally only necessary if the native - type is allowed to be subclasses from JS code (at which point - the JS 'this' is not the same exact object as the one - holding the native 'this' pointer, and we need to search the - prototype chain). - - For this all to work: the class-binding mechanism being used - by the client must store the TypeID value in all new - JS-created instances of T by calling SetInternalField( - TypeIdFieldIndex, theTypeID ) and store the native object - pointer in the field internal field ObjectFieldIndex. And - then they should do: - - @code - // in the cvv8 namespace: - template <> - struct JSToNative : - JSToNative_ObjectWithInternalFieldsTypeSafe - {}; - @endcode - - At which point CastFromJS() will take advantage of this - type check. - - - The real docs end here. What follows is pseudorandom blather... - - Theoretically (i haven't tried this but i know how the - underlying code works), it is possible for script code to - create a condition which will lead to an invalid cast if the - check performed by this class (or something equivalent) is - _not_ performed: - - @code - var x = new Native1(); - var y = new Native2(); - // assume y.someFunc and x.otherFunc are both bound to native functions - y.someFunc = x.otherFunc; - y.someFunc( ... ); // here is where it will likely end badly - @endcode - - When y.someFunc() is called, JS will look for a 'this' object of - type Native1, not Native2, because the type information related to - the conversion is "stored" in the callback function itself, not in - the native object. (This is a side-effect of us using templates to - create InvocationCallback implementations.) It will not find a - Native1, but it might (depending on how both classes are bound to - JS) find a Native2 pointer and _think_ it is a Native1. And by - "think it is" i mean "it will try to cast it to," but the cast is - illegal in that case. In any case it would be bad news. - - The check performed by this class can catch that condition - (and similar ones) and fail gracefully (i.e. returning a - NULL instead of performing an illegal cast). - */ - template - struct JSToNative_ObjectWithInternalFieldsTypeSafe - { - private: - typedef char AssertIndexRanges - [(InternalFieldCount>=2) - && (TypeIdFieldIndex != ObjectFieldIndex) - && (TypeIdFieldIndex >= 0) - && (TypeIdFieldIndex < InternalFieldCount) - && (ObjectFieldIndex >= 0) - && (ObjectFieldIndex < InternalFieldCount) - ? 1 : -1]; - public: - typedef typename TypeInfo::NativeHandle ResultType; - /** - If h is-a Object and it meets the requirements described - in this class' documentation, then this function returns - the result of static_cast(void*), using the (void*) - extracted from the Object. If the requirements are not met - then NULL is returned. - - See the class docs for more details on the requirements - of the passed-in handle. - - If SearchPrototypeChain is true and the object does not - contain a native then the prototype chain is searched - recursively. This is generally only required when bound - types are subclassed from JS code. - */ - ResultType operator()( v8::Handle const & h ) const - { - if( h.IsEmpty() || ! h->IsObject() ) return NULL; - else - { - void const * tid = NULL; - void * ext = NULL; - v8::Handle proto(h); - while( !ext && !proto.IsEmpty() && proto->IsObject() ) - { - v8::Local const & obj( v8::Object::Cast( *proto ) ); - tid = (obj->InternalFieldCount() != InternalFieldCount) - ? NULL - : obj->GetPointerFromInternalField( TypeIdFieldIndex ); - ext = (tid == TypeID) - ? obj->GetPointerFromInternalField( ObjectFieldIndex ) - : NULL; - if( ! ext ) - { - if( ! SearchPrototypeChain ) break; - else proto = obj->GetPrototype(); - } - } - return ext ? static_cast(ext) : NULL; - } - } - }; - - /** Specialization to convert JS values to int16_t. */ - template <> - struct JSToNative - { - typedef int16_t ResultType; - ResultType operator()( v8::Handle const & h ) const - { - return h->IsNumber() - ? static_cast(h->Int32Value()) - : 0; - } - }; - - /** Specialization to convert JS values to uint16_t. */ - template <> - struct JSToNative - { - typedef uint16_t ResultType; - ResultType operator()( v8::Handle const & h ) const - { - return h->IsNumber() - ? static_cast(h->Int32Value()) - : 0; - } - }; - - /** Specialization to convert JS values to int32_t. */ - template <> - struct JSToNative - { - typedef int32_t ResultType; - ResultType operator()( v8::Handle const & h ) const - { - return h->IsNumber() - ? h->Int32Value() - : 0; - } - }; - - /** Specialization to convert JS values to uint32_t. */ - template <> - struct JSToNative - { - typedef uint32_t ResultType; - ResultType operator()( v8::Handle const & h ) const - { - return h->IsNumber() - ? static_cast(h->Uint32Value()) - : 0; - } - }; - - - /** Specialization to convert JS values to int64_t. */ - template <> - struct JSToNative - { - typedef int64_t ResultType; - ResultType operator()( v8::Handle const & h ) const - { - return h->IsNumber() - ? static_cast(h->IntegerValue()) - : 0; - } - }; - - /** Specialization to convert JS values to uint64_t. */ - template <> - struct JSToNative - { - typedef uint64_t ResultType; - ResultType operator()( v8::Handle const & h ) const - { - return h->IsNumber() - ? static_cast(h->IntegerValue()) - : 0; - } - }; - - /** Specialization to convert JS values to double. */ - template <> - struct JSToNative - { - typedef double ResultType; - ResultType operator()( v8::Handle const & h ) const - { - return h->IsNumber() - ? h->NumberValue() - : 0; - } - }; - - /** Specialization to convert JS values to bool. */ - template <> - struct JSToNative - { - typedef bool ResultType; - ResultType operator()( v8::Handle const & h ) const - { - return h->BooleanValue(); - } - }; - - /** Specialization to convert JS values to std::string. */ - template <> - struct JSToNative - { - typedef std::string ResultType; - ResultType operator()( v8::Handle const & h ) const - { - static const std::string emptyString; - v8::String::Utf8Value const utf8String( h ); - const char* s = *utf8String; - return s - ? std::string(s, utf8String.length()) - : emptyString; - } - }; - - /** - Specialization necessary to avoid incorrect default behaviour - for this special case. - - Reminder to self: we'll need a specialization like this any - time we want to use a type which is returned by VALUE from - JSToNative() and might be passed as a const reference as a - function argument type. The vast majority of bound native - types are bound internally as pointers (and don't need a - specialization like this one), whereas the std::string - conversion uses value semantics to simplify usage. - */ - template <> - struct JSToNative : public JSToNative {}; - -#if 0 // leave this unused code here for the sake of the next guy who tries to re-add it - /** - Nonono! This will Cause Grief when used together with CastFromJS() - because the returned pointer's lifetime cannot be guaranteed. - See ArgCaster for more details on the problem. - */ - template <> - struct JSToNative - { - public: - typedef char const * ResultType; - ResultType operator()( v8::Handle const & h ); - }; -#else -#if 0 // it turns out no current (20110627) code uses this. -// We might want to leave it in b/c that will cause compile errors -// in some use cases rather than link errors ("undefined ref..."). - /** Not great, but a happy medium. */ - template <> - struct JSToNative : JSToNative {}; -#endif -#endif - - namespace Detail - { - /** A kludge placeholder type for a ulong-is-not-uint64 - condition on some platforms. - - T is ignored, but is required to avoid class-redefinition - errors for the templates using this class. - */ - template - struct UselessConversionType - { - }; - } - - /** - This specialization is a kludge/workaround for use in cases - where (unsigned long int) is: - - 1) The same type as the platform's pointer type. - 2) Somehow NOT the same as one of the standard uintNN_t types. - 3) Used in CastToJS() or CastFromJS() calls. - - If ulong and uint64 are the same type then this specialization - is a no-op (it generates a converter for a type which will - never be converted), otherwords it performs a numeric conversion. - */ - template <> - struct NativeToJS< tmp::IfElse< tmp::SameType::Value, - Detail::UselessConversionType, - unsigned long >::Type > - : Detail::NativeToJS_int_big - { - }; - - /** - This is a kludge/workaround for use in cases where (unsigned - long int) is: - - 1) The same type as the platform's pointer type. - 2) Somehow NOT the same as one of the standard uintNN_t types. - 3) Used in CastToJS() or CastFromJS() calls. - - If ulong and uint64 are the same type then this specialization - is a no-op (it generates a converter for a type which will - never be converted), otherwords it performs a numeric - conversion. - */ - template <> - struct JSToNative< tmp::IfElse< - tmp::SameType::Value, - Detail::UselessConversionType, - unsigned long >::Type > - : JSToNative - { - }; - - /** - See the equivalent NativeToJS kludge for unsigned long. - */ - template <> - struct NativeToJS< tmp::IfElse< tmp::SameType::Value, - Detail::UselessConversionType, - long >::Type > - : Detail::NativeToJS_int_big - { - }; - - /** - See the equivalent JSToNative kludge for unsigned long. - */ - template <> - struct JSToNative< tmp::IfElse< - tmp::SameType::Value, - Detail::UselessConversionType, - long >::Type > : JSToNative - { - }; - -#if CVV8_CONFIG_HAS_LONG_LONG - /** - See the equivalent JSToNative kludge for unsigned long. - - Added 20100606 to please the sqlite3 plugin, where sqlite3_int64 - collides with (long long) on some platforms and causes an invalid - conversion compile-time error. - */ - template <> - struct JSToNative< tmp::IfElse< - tmp::SameType::Value, - Detail::UselessConversionType, - long long int >::Type > : JSToNative - { - }; - /** - See the equivalent JSToNative kludge for unsigned long. - - Added 20101126 to please the sqlite3 plugin, where - sqlite3_int64 collides with (long long) on some platforms and - causes a link-time error. - */ - template <> - struct NativeToJS< tmp::IfElse< tmp::SameType::Value, - Detail::UselessConversionType, - long long int >::Type > - : Detail::NativeToJS_int_big - { - }; -#endif - - - /** - Converts h to an object of type NT, using JSToNative to do - the conversion. - */ - template - typename JSToNative::ResultType CastFromJS( v8::Handle const & h ) - { - typedef JSToNative F; - return F()( h ); - } - - /** Convenience instance of JSToNative. */ - static const JSToNative JSToInt16 = JSToNative(); - /** Convenience instance of JSToNative. */ - static const JSToNative JSToUInt16 = JSToNative(); - /** Convenience instance of JSToNative. */ - static const JSToNative JSToInt32 = JSToNative(); - /** Convenience instance of JSToNative. */ - static const JSToNative JSToUInt32 = JSToNative(); - /** Convenience instance of JSToNative. */ - static const JSToNative JSToInt64 = JSToNative(); - /** Convenience instance of JSToNative. */ - static const JSToNative JSToUInt64 = JSToNative(); - /** Convenience instance of JSToNative. */ - static const JSToNative JSToDouble = JSToNative(); - /** Convenience instance of JSToNative. */ - static const JSToNative JSToBool = JSToNative(); - /** Convenience instance of JSToNative. */ - static const JSToNative JSToStdString = JSToNative(); - - /** - A utility to add properties to a JS v8::Object or v8::ObjectTemplate. - ObjectType must be either v8::Object or v8::ObjectTemplate. It - _might_ work in limited context with v8::Array, but that is untested. - ObjectType is intended to be v8::Object or v8::ObjectTemplate, - but Object subclasses, e.g. v8::Array and v8::Function, "should" work - as well. - - It is intended to be used like this: - - \code - v8::Handle obj = ...; - ObjectPropSetter set(obj); - set("propOne", CastToJS(32) ) - ("propTwo", ... ) - (32, ... ) - ("func1", anInvocationCallback ) - ; - \endcode - */ - template ::Value, - v8::Handle, - v8::Handle - >::Type - > - class ObjectPropSetter - { - private: - v8::Handle const target; - public: - /** - Initializes this object to use the given array - as its append target. Results are undefined if - target is not a valid Object. - */ - explicit ObjectPropSetter( v8::Handle< ObjectType > const & obj ) :target(obj) - {} - ~ObjectPropSetter(){} - - - /** - Adds an arbtirary property to the target object. - */ - inline ObjectPropSetter & Set( KeyType const & key, v8::Handle const & v ) - { - this->target->Set(key->ToString(), CastToJS(v)); - return *this; - } - /** - Adds an arbtirary property to the target object. - */ - inline ObjectPropSetter & Set( char const * key, v8::Handle const & v ) - { - this->target->Set( v8::String::New(key), CastToJS(v)); - return *this; - } - - /** - Adds an arbitrary property to the target object using - CastToJS(v). - */ - template - inline ObjectPropSetter & operator()( KeyType const & key, T const & v ) - { - this->target->Set(key, CastToJS(v)); - return *this; - } - - /** - Adds a numeric property to the target object. - */ - template - inline ObjectPropSetter & operator()( int32_t ndx, T const & v ) - { - return this->Set( v8::Integer::New(ndx), CastToJS(v) ); - } - - /** - Adds a string-keyed property to the target object. - Note that if key is NULL, the v8::String constructor - will crash your app. (Good luck with that!) - */ - template - inline ObjectPropSetter & operator()( char const * key, T const & v ) - { - return this->Set( v8::String::New(key), CastToJS(v) ); - } - - - /** - Adds the given function as a member of the target object. - */ - inline ObjectPropSetter & operator()( char const * name, v8::InvocationCallback pf ) - { - return this->Set( name, v8::FunctionTemplate::New(pf)->GetFunction() ); - } - - /** - Returns this object's JS object. - */ - v8::Handle< v8::Object > Object() const - { - return this->target; - } - }; - - /** - NativeToJS classes which act on list types compatible with the - STL can subclass this to get an implementation. - */ - template - struct NativeToJS_list - { - v8::Handle operator()( ListT const & li ) const - { - typedef typename ListT::const_iterator IT; - IT it = li.begin(); - const size_t sz = li.size(); -#if 1 - v8::Handle rv( v8::Array::New( static_cast(sz) ) ); - for( int i = 0; li.end() != it; ++it, ++i ) - { - rv->Set( v8::Integer::New(i), CastToJS( *it ) ); - } - return rv; -#else - ObjectPropSetter app(Array::New( static_cast(sz) )); - for( int32_t i = 0; li.end() != it; ++it, ++i ) - { - app( i, CastToJS( *it ) ); - } - return app.Object(); -#endif - } - }; - - /** Partial specialization for std::list<>. */ - template - struct NativeToJS< std::list > : NativeToJS_list< std::list > {}; - /** Partial specialization for std::vector<>. */ - template - struct NativeToJS< std::vector > : NativeToJS_list< std::vector > {}; - - /** - NativeToJS classes which act on map types compatible with the - STL can subclass this to get an implementation. - - Both the key and mapped types of the given Map Type must be - converitible to v8 types using CastToJS(). - */ - template - struct NativeToJS_map - { - v8::Handle operator()( MapT const & li ) const - { - typedef typename MapT::const_iterator IT; - IT it( li.begin() ); - v8::Handle rv( v8::Object::New() ); - for( int i = 0; li.end() != it; ++it, ++i ) - { - rv->Set( CastToJS( (*it).first ), CastToJS( (*it).second ) ); - } - return rv; - } - }; - - /** Partial specialization for std::map<>. */ - template - struct NativeToJS< std::map > : NativeToJS_map< std::map > {}; - - /** - A base class for JSToNative - specializations. ListT must be compatible with std::list and - std::vector, namely: - - - Must support push_back( ListT::value_type ). - - - Must define value_type typedef or the second template - argument must be specified for this template. - - It is technically legal for ValueType to differ from - ListT::value_type if - ListT::push_back(JSToNative::ResultType) is - legal. e.g. if ListT is std::vector and we want to - truncate the values we could use, e.g. int32_t as the - ValueType. - */ - template - struct JSToNative_list - { - typedef ListT ResultType; - /** - Converts jv to a ListT object. - - If jv->IsArray() then the returned object is populated from - jv, otherwise the returned object is empty. Since it is - legal for an array to be empty, it is not generically - possible to know if this routine got an empty Array object - or a non-Array object. - */ - ResultType operator()( v8::Handle jv ) const - { - //typedef typename ListT::value_type VALT; - typedef ValueType VALT; - ListT li; - if( jv.IsEmpty() || ! jv->IsArray() ) return li; - v8::Handle ar( v8::Array::Cast(*jv) ); - uint32_t ndx = 0; - for( ; ar->Has(ndx); ++ndx ) - { - li.push_back( CastFromJS( ar->Get(v8::Integer::New(ndx)) ) ); - } - return li; - } - }; - - /** Partial specialization for std::list<>. */ - template - struct JSToNative< std::list > : JSToNative_list< std::list > {}; - - /** Partial specialization for std::vector<>. */ - template - struct JSToNative< std::vector > : JSToNative_list< std::vector > {}; - -#if 0 // untested code - /** - UNTESTED! - - Intended as a base class for JSToNative specializations - which proxy a std::map-like map. - */ - template - struct JSToNative_map - { - typedef MapT ResultType; - /** - Converts jv to a MapT object. - - If jv->IsObject() then the returned object is populated from - jv, otherwise the returned object is empty. Since it is - legal for an object to be empty, it is not generically - possible to know if this routine got an empty Object - or a non-Object handle. - */ - ResultType operator()( v8::Handle jv ) const - { - typedef ValueType VALT; - MapT map; - if( jv.IsEmpty() || ! jv->IsObject() ) return map; - Local obj( Object::Cast(*jv) ); - Local ar( obj->GetPropertyNames() ); - uint32_t ndx = 0; - for( ; ar->Has(ndx); ++ndx ) - { - Local const & k = ar->Get(Integer::New(ndx)); - if( ! obj->HasRealNamedProperty(k) ) continue; - map[CastFromJS(k)] = CastFromJS(obj->Get(k)); - } - return map; - } - }; -#endif - /** - A utility class for building up message strings, most notably - exception messages, using a mixture of native and JS message - data. - - It is used like a std::ostream: - - @code - StringBuffer msg; - msg << "Could not set property " - << "'" << propName - <<"' on object " << myJSObject << '!'; - return v8::ThrowException(msg.toError()); - // or: - return Toss(msg); - @endcode - */ - class StringBuffer - { - private: - std::ostringstream os; - public: - /** - Initializes the message stream. - */ - StringBuffer() : os() - { - } - StringBuffer(StringBuffer const & other) : os(other.os.str()) - { - } - StringBuffer & operator=(StringBuffer const & other) - { - this->os.str(other.os.str()); - return *this; - } - - /** - Empties out the message buffer. This invalidates any value - returned from previous calls to the (char const *) - operator. - */ - inline void Clear() - { - this->os.str(""); - } - - /** - Returns a copy of the current message content. - */ - inline std::string Content() const - { - return this->os.str(); - } - - /** - Converts the message state to a JS string. - */ - inline operator v8::Handle() const - { - return CastToJS( this->os.str() ); - } - - /** - Converts the message state to a v8::String (for use - with v8::Exception::Error() and friends). - */ - inline operator v8::Handle() const - { - std::string const & str(this->os.str()); - char const * cstr = str.c_str(); - return v8::String::New( cstr ? cstr : "", cstr ? str.size() : 0 ); - } - - /** - Appends to the message using CastFromJS(t) - */ - template - inline StringBuffer & operator<<( v8::Handle const & t ) - { - this->os << CastFromJS( t ); - return *this; - } - /** - Appends to the message using CastFromJS(t) - - Reminder to self: if this function is changed to take - a const reference instead of a copy, we get overload - ambiguity errors in some contexts. See: - - http://code.google.com/p/v8-juice/issues/detail?id=19 - - (And thanks to Feng Fillano for reporting and localizing - the problem.) - */ - template - inline StringBuffer & operator<<( v8::Local const t ) - { - this->os << CastFromJS( t ); - return *this; - } - - /** - Appends t to the message via std::ostream<<. - */ - template - inline StringBuffer & operator<<( T const t) - { - this->os << t; - return *this; - } - - /** - Returns this buffer's value wrapped in - a JS Error object. - */ - v8::Local toError() const - { - return v8::Exception::Error(*this); - } - }; - - /** Outputs sb.Content() to os and returns os. */ - inline std::ostream & operator<<( std::ostream & os, StringBuffer const & sb ) - { - return os << sb.Content(); - } - - - /** - Requi - "Lexically casts" msg to a string and throws a new JS-side - Error. ValT may be any type which can be sent to StringBuffer's - ostream operator. - - The return value is the result of calling - v8::ThrowException() (Undefined except in the face of a - serious internal error like OOM, i'm told by the v8 devs). - */ - template - inline v8::Handle Toss( ValT const & msg ) - { - return v8::ThrowException((StringBuffer() << msg).toError()); - } - - /** - Overload to avoid an ambiguity (and it's more efficient than - the default impl). - */ - inline v8::Handle Toss( char const * msg ) - { - return v8::ThrowException(v8::Exception::Error(v8::String::New( msg ? msg : "Unspecified error."))); - } - - /** - Eqivalent to v8::ThrowException(err). Note that if err is not an - Error object, the JS side will not get an Error object. e.g. if err - is-a String then the JS side will see the error as a string. - - The reason this does not convert err to an Error is because the v8 - API provides no way for us to know if err is already an Error object. - This function is primarily intended to be passed the results of - CastToJS(std::exception), which generates Error objects. - */ - inline v8::Handle Toss( v8::Handle const & err ) - { - return v8::ThrowException(err); - } - - /** - Efficiency overload. - */ - inline v8::Handle Toss( StringBuffer const & msg ) - { - return v8::ThrowException(msg.toError()); - } - /** - Like Toss(Handle), but converts err to a string and creates an - Error object, which is then thrown. - */ - inline v8::Handle TossAsError( v8::Handle const & err ) - { - return Toss(v8::Exception::Error(err->ToString())); - } - - /** - ArgCaster is a thin wrapper around CastFromJS(), and primarily - exists to give us a way to convert JS values to (char const *) - for purposes of passing them to native functions. The main - difference between this type and JSToNative is that this - interface explicitly allows for the conversion to be stored by - an instance of this type. That allows us to get more lifetime - out of converted values in certain cases (namely (char const*)). - - The default implementation is suitable for all cases which - JSToNative supports, but specializations can handle some of - the corner cases which JSToNative cannot (e.g. (char const *)). - - Added 20091121. - */ - template - struct ArgCaster - { - typedef typename JSToNative::ResultType ResultType; - /** - Default impl simply returns CastFromJS(v). - Specializations are allowed to store the result of the - conversion, as long as they release it when the destruct. - See ArgCaster for an example of that. - */ - inline ResultType ToNative( v8::Handle const & v ) const - { - return CastFromJS( v ); - } - /** - To eventually be used for some internal optimizations. - */ - enum { HasConstOp = 1 }; - }; - /** - Specialization for (char const *). The value returned from - ToNative() is guaranteed to be valid as long as the ArgCaster - object is alive or until ToNative() is called again (which will - almost certainly change the pointer). Holding a pointer to the - ToNative() return value after the ArgCaster is destroyed will - lead to undefined behaviour. Likewise, fetching a pointer, then - calling ToNative() a second time, will invalidate the first - pointer. - - BEWARE OF THESE LIMITATIONS: - - 1) This will only work properly for nul-terminated strings, - and not binary data! - - 2) Do not use this to pass (char const *) as a function - parameter if that function will hold a copy of the pointer - after it returns (as opposed to copying/consuming the - pointed-to-data before it returns) OR if it returns the - pointer passed to it. Returning is a specific corner-case - of "holding a copy" for which we cannot guaranty the lifetime - at the function-binding level. - - 3) Do not use the same ArgCaster object to convert multiple - arguments, as each call to ToNative() will invalidate the - pointer returned by previous calls. - - 4) The to-string conversion uses whatever encoding - JSToNative uses. - - Violating any of those leads to undefined behaviour, and - very possibly memory corruption for cases 2 or 3. - */ - template <> - struct ArgCaster - { - private: - /** - Reminder to self: we cannot use v8::String::Utf8Value - here because at the point the bindings call ToNative(), - v8 might have been unlocked, at which point dereferencing - the Utf8Value becomes illegal. - */ - std::string val; - typedef char Type; - public: - typedef Type const * ResultType; - /** - Returns the toString() value of v unless: - - - v.IsEmpty() - - v->IsNull() - - v->IsUndefined() - - In which cases it returns 0. - - The returned value is valid until: - - - ToNative() is called again. - - This object is destructed. - */ - ResultType ToNative( v8::Handle const & v ) - { - typedef JSToNative C; - if( v.IsEmpty() || v->IsNull() || v->IsUndefined() ) - { - return 0; - } - this->val = C()( v ); - return this->val.c_str(); - } - /** - To eventually be used for some internal optimizations. - */ - enum { HasConstOp = 0 }; - }; - -#if !defined(DOXYGEN) - namespace Detail { - /** - Default (unimplemented) CtorForwarderProxy impl. A helper - for the CtorForwarder class. All specializations except - the 0-arity one are generated from script code. - */ - template >::Value > - struct CtorForwarderProxy - { - typedef typename Signature::ReturnType ReturnType; - static ReturnType Call( v8::Arguments const & ); - }; - - //! Specialization for 0-arity ctors. - template - struct CtorForwarderProxy - { - typedef typename Signature::ReturnType ReturnType; - static ReturnType Call( v8::Arguments const & ) - { - typedef typename TypeInfo::Type RType; - return new RType; - } - }; - //! Specialization for ctors taking (v8::Arguments const &). - template - struct CtorForwarderProxy - { - typedef typename Signature::ReturnType ReturnType; - static ReturnType Call( v8::Arguments const & argv ) - { - typedef typename TypeInfo::Type T; - return new T(argv); - } - }; - - } -#endif - /** - A utility type to help forward v8::Arguments to native - constructors. This type is intended to assist in the creation - of ctor functions for JS-bound C++ classes. - - Requirements: - - - Sig is "almost" a function-signature-style type, but - because ctors don't have a return value in the conventional - sense, we have to use a tiny workaround: Sig should be passed - in like this from client code: - - @code - typedef CtorForwarder CF; - @endcode - - - (new T(...)) must be legal, taking a number of - arguments equal to Sig's Arity. - - - All arguments to the native ctor must be convertible - using CastFromJS(). - - Example: - - @code - typedef CtorForwarder CF0; - typedef CtorForwarder CF1; - typedef CtorForwarder CF2; - typedef CtorForwarder CFAny; - @endcode - - @see CtorArityDispatcher - */ - template - struct CtorForwarder : Signature - { - typedef Signature STL; - //typedef typename tmp::AddPointer::Type ReturnType; - typedef typename STL::ReturnType ReturnType; - /** - If (argv.Length()>=Arity) or Arity is less than 0, - then the constructor is called with Arity arguments - (if it >=0) or with 1 v8::Arguments parameter (for Arity<0). - - Returns the result of (new Type(...)), transfering ownership - to the caller. - - May propagate native exceptions. - */ - static ReturnType Call( v8::Arguments const & argv ) - { - enum { Arity = sl::Arity< STL >::Value }; - typedef Detail::CtorForwarderProxy Proxy; - return Proxy::Call( argv ); - } - }; - -#if !defined(DOXYGEN) - namespace Detail - { - - /** - Internal dispatch routine. CTOR _must_ be a CtorForwarder implementation - (or interface-compatible). - */ - template - struct CtorFwdDispatch - { - typedef typename TypeInfo::NativeHandle ReturnType; - static ReturnType Call( v8::Arguments const & argv ) - { - return CTOR::Call( argv ); - } - }; - /** - Internal dispatch end-of-list routine. - */ - template - struct CtorFwdDispatch - { - typedef typename TypeInfo::NativeHandle ReturnType; - static ReturnType Call( v8::Arguments const & ) - { - return 0; - } - }; - /** - Internal type to dispatch a v8::Arguments list to one of - several a bound native constructors, depending on on the - argument count. - - List MUST be a Signature< ... > containing ONLY - CtorFowarder types (or compatible). - */ - template - struct CtorFwdDispatchList - { - typedef typename TypeInfo::NativeHandle ReturnType; - /** - Tries to dispatch Arguments to one of the constructors - in the List type, based on the argument count. - */ - static ReturnType Call( v8::Arguments const & argv ) - { - typedef typename List::Head CTOR; - typedef typename List::Tail Tail; - enum { Arity = (0==sl::Index::Value) - ? -1 : sl::Length::Value - }; - return ( (Arity < 0) || (Arity == argv.Length()) ) - ? CtorFwdDispatch< T, CTOR >::Call(argv ) - : CtorFwdDispatchList::Call(argv); - } - }; - /** - End-of-list specialization. - */ - template - struct CtorFwdDispatchList - { - typedef typename TypeInfo::NativeHandle ReturnType; - /** Writes an error message to errmsg and returns 0. */ - static ReturnType Call( v8::Arguments const & argv ) - { - StringBuffer msg; - msg << "No native constructor was defined for "<, - CtorForwarder, - CtorForwarder, - CtorForwarder - )> Ctors; - @endcode - - All entries in the typelist must be interface-compatible with - CtorForwarder. No two entries should have the same number - of arguments with one exception: an InvocationCallback-like - function taking (v8::Arguments const &) can be used as a - catch-all for any number of arguments. If used, it must be - the LAST entry because it will always match any argument - count (and will therefore trump any which (would) come after - it. - - The ctors are dispatched based solely on the argument count, - not their types. The first one with a matching arity - is called. - - IN THEORY (untested), the factories passed in the list may - legally return a type publically derived from - CtorList::ReturnType. - */ - template - struct CtorArityDispatcher - { - typedef typename CtorList::ReturnType RT; - typedef typename TypeInfo::NativeHandle NativeHandle; - static NativeHandle Call( v8::Arguments const & argv ) - { - typedef typename tmp::PlainType::Type Type; - typedef Detail::CtorFwdDispatchList Proxy; - return Proxy::Call( argv ); - } - }; - -} // namespaces - - -#endif /* CODE_GOOGLE_COM_P_V8_CONVERT_CORE_HPP_INCLUDED */ diff --git a/vendor/libv8-convert/cvv8/detail/doxygen_hack.hpp b/vendor/libv8-convert/cvv8/detail/doxygen_hack.hpp deleted file mode 100644 index 85778705d..000000000 --- a/vendor/libv8-convert/cvv8/detail/doxygen_hack.hpp +++ /dev/null @@ -1,28 +0,0 @@ -/** @file doxygen_hack.hpp - - doxygen REFUSES to document class templates i forward-decl, even when - adding "@class" to the docs. Being the doc-pedant that i am, i felt - compelled to work around that. With gcc we can add an empty body to - those classes but MSVC doesn't like it. So we leave it out unless - doxygen is building, and then doxygen needs to be configured with: - - - ENABLE_PREPROCESSING = YES - - EXPAND_AS_DEFINED = DOXYGEN_FWD_DECL_KLUDGE - - and possibly: - - - MACRO_EXPANSION = YES - - and/or: - - - EXPAND_ONLY_PREDEF = YES -*/ -#if !defined(DOXYGEN) -# if !defined DOXYGEN_FWD_DECL_KLUDGE -# define DOXYGEN_FWD_DECL_KLUDGE -# endif -#else -# if !defined DOXYGEN_FWD_DECL_KLUDGE -# define DOXYGEN_FWD_DECL_KLUDGE {} -# endif -#endif diff --git a/vendor/libv8-convert/cvv8/detail/invocable_core.hpp b/vendor/libv8-convert/cvv8/detail/invocable_core.hpp deleted file mode 100644 index a47b3dcb8..000000000 --- a/vendor/libv8-convert/cvv8/detail/invocable_core.hpp +++ /dev/null @@ -1,2202 +0,0 @@ -#if !defined(CODE_GOOGLE_COM_V8_CONVERT_INVOCABLE_V8_HPP_INCLUDED) -#define CODE_GOOGLE_COM_V8_CONVERT_INVOCABLE_V8_HPP_INCLUDED 1 - -/** @file invocable_core.hpp - -This file houses the core-most "invocation-related" parts of the -v8-convert API. These types and functions are for converting -free and member functions to v8::InvocationCallback functions -so that they can be tied to JS objects. It relies on the -CastToJS() and CastFromJS() functions to do non-function type -conversion. - -*/ - -#include "convert_core.hpp" -#include "signature_core.hpp" - -namespace cvv8 { - -/** - A concept class, primarily for documentation and tag-type purposes. -*/ -struct InCa -{ - /** - Matches the v8::InvocationCallback interface. All function bindings - created by this framework use Call() as their class-level - InvocationCallback interface. Some bindings provide additional - overloads as well. - */ - static v8::Handle Call( v8::Arguments const & ); -}; - -/** - A tag type for use with FunctionTo and MethodTo. -*/ -struct InCaVoid : InCa {}; - - -/** - Partial specialization for v8::InvocationCallback-like functions - (differing only in their return type) with an Arity value of -1. -*/ -template -struct FunctionSignature< RV (v8::Arguments const &) > : Signature -{ - typedef RV (*FunctionType)(v8::Arguments const &); -}; - -/** - Partial specialization for v8::InvocationCallback-like non-const - member functions (differing only in their return type) with an - Arity value of -1. -*/ -template -struct MethodSignature< T, RV (v8::Arguments const &) > : Signature< RV (v8::Arguments const &) > -{ - typedef T Type; - typedef RV (T::*FunctionType)(v8::Arguments const &); -}; - -/** - Partial specialization for v8::InvocationCallback-like const member - functions (differing only in their return type) with an Arity value - of -1. -*/ -template -struct ConstMethodSignature< T, RV (v8::Arguments const &) > : Signature< RV (v8::Arguments const &) > -{ - typedef T Type; - typedef RV (T::*FunctionType)(v8::Arguments const &) const; -}; - -/** - Full specialization for InvocationCallback and - InvocationCallback-like functions (differing only by their return - type), which uses an Arity value of -1. -*/ -template -struct FunctionPtr - : FunctionSignature -{ - public: - typedef FunctionSignature SignatureType; - typedef typename SignatureType::ReturnType ReturnType; - typedef typename SignatureType::FunctionType FunctionType; - static FunctionType GetFunction() - { - return FuncPtr; - } -}; - -/** - Full specialization for InvocationCallback and - InvocationCallback-like functions (differing only by their return - type), which uses an Arity value of -1. -*/ -template -struct MethodPtr - : MethodSignature -{ - typedef MethodSignature SignatureType; - typedef typename SignatureType::ReturnType ReturnType; - typedef typename SignatureType::FunctionType FunctionType; - static FunctionType GetFunction() - { - return FuncPtr; - } -}; - -/** - Full specialization for InvocationCallback and - InvocationCallback-like functions (differing only by their return - type), which uses an Arity value of -1. -*/ -template -struct ConstMethodPtr - : ConstMethodSignature -{ - typedef ConstMethodSignature SignatureType; - typedef typename SignatureType::ReturnType ReturnType; - typedef typename SignatureType::FunctionType FunctionType; - static FunctionType GetFunction() - { - return FuncPtr; - } -}; - -#if !defined(DOXYGEN) -namespace Detail { - /** - A sentry class which instantiates a v8::Unlocker - if the boolean value is true or is a no-op if it is false. - */ - template struct V8Unlocker {}; - - /** - Equivalent to v8::Unlocker. - */ - template <> - struct V8Unlocker : v8::Unlocker - { - }; - - -} -#endif - -/** - A metatemplate which we can use to determine if a given type - is "safe" to use in conjunction with v8::Unlock. - - We optimistically assume that most types are safe and - add specializations for types we know are not safe, e.g. - v8::Handle and v8::Arguments. - - Specializations of this type basically make up a collective - "blacklist" of types which we know are not legal to use unless - v8 is locked by our current thread. As new problematic types are - discovered, they can be added to the blacklist by introducing a - specialization of this class. -*/ -template -struct IsUnlockable : tmp::BoolVal {}; -template -struct IsUnlockable : IsUnlockable {}; -template -struct IsUnlockable : IsUnlockable {}; -template -struct IsUnlockable : IsUnlockable {}; -template -struct IsUnlockable : IsUnlockable {}; - -/** - Explicit instantiation to make damned sure that nobody - re-sets this one. We rely on these semantics for - handling FunctionSignature like Const/MethodSignature - in some cases. -*/ -template <> -struct IsUnlockable : tmp::BoolVal {}; - -/* - Todo?: find a mechanism to cause certain highly illegal types to - always trigger an assertion... We could probably do it by - declaring but not definiting JSToNative/NativeToJS - specialializations. -*/ -template <> -struct IsUnlockable : tmp::BoolVal {}; - -template <> -struct IsUnlockable : tmp::BoolVal {}; - -template -struct IsUnlockable< v8::Handle > : tmp::BoolVal {}; - -template -struct IsUnlockable< v8::Persistent > : tmp::BoolVal {}; - -template -struct IsUnlockable< v8::Local > : tmp::BoolVal {}; - -template <> -struct IsUnlockable : tmp::BoolVal {}; - -/** - Given a tmp::TypeList-compatible type list, this metafunction's - Value member evalues to true if IsUnlockable::Value is - true for all types in TList, else Value evaluates to false. - As a special case, an empty list evaluates to true because in this - API an empty list will refer to a function taking no arguments. -*/ -template -struct TypeListIsUnlockable : tmp::BoolVal< - IsUnlockable::Value && TypeListIsUnlockable::Value - > -{ -}; - -//! End-of-typelist specialization. -template <> -struct TypeListIsUnlockable< tmp::NilType > : tmp::BoolVal -{}; -/** - Given a Signature, this metafunction's Value member - evaluates to true if: - - - IsUnlockable::Value is true and... - - - IsUnlockable::Value is true (only relavent - for Const/MethodSignature, not FunctionSignature) and... - - - TypeListIsUnlockable< SigTList >::Value is true. - - If the value is true, the function signature has passed the most - basic check for whether or not it is legal to use v8::Unlocker - to unlock v8 before calling a function with this signature. Note - that this is a best guess, but this code cannot know - app-specific conditions which might make this guess invalid. - e.g. if a bound function itself uses v8 and does not explicitly - acquire a lock then the results are undefined (and will very - possibly trigger an assertion in v8, killing the app). Such - things can and do happen. If you're lucky, you're building - against a debug version of libv8 and its assertion text will - point you directly to the JS code which caused the assertion, - then you can disable unlocking support for that binding. - - If you want to disable unlocking for all bound members of a given - class, create an IsUnlockable specialization whos Value - member evaluates to false. Then no functions/methods using that - class will cause this metafunction to evaluate to true. - - Note that FunctionToInCa, Const/MethodToInCa, etc., are all - Signature subclasses, and can be used directly with - this template. - - Example: - - @code - // This one can be unlocked: - typedef FunctionSignature< int (int) > F1; - // SignatureIsUnlockable::Value == true - - // This one cannot because it contains a v8 type in the arguments: - typedef FunctionSignature< int (v8::Handle) > F2; - // SignatureIsUnlockable::Value == false - @endcode - - For Const/MethodToInCa types, this check will also fail if - IsUnlockable< SigTList::Context >::Value is false. -*/ -template -struct SignatureIsUnlockable : tmp::BoolVal< - IsUnlockable::Value && - IsUnlockable::Value && - IsUnlockable::Value && - SignatureIsUnlockable::Value - > {}; -//! End-of-list specialization. -template <> -struct SignatureIsUnlockable : tmp::BoolVal {}; - -/** - Internal exception type to allow us to differentiate - "no native 'this' pointer found" errors from all other - exceptions. It is thrown by the CallNative() functions - of various JS-to-Native function forwarders. -*/ -struct MissingThisException -{ -protected: - StringBuffer msg; - template - void init() - { - this->msg << "CastFromJS<"<< TypeName::Value - << ">() returned NULL. Throwing to avoid " - << "dereferencing a NULL pointer!"; - } - MissingThisException() {} -public: - /** - Returns the exception message text, which does not change - after construction. - */ - StringBuffer const & Buffer() const { return msg; } -}; - - -/** - This special-case convenience form of Toss() triggers a JS-side - exception containing an English-language message explaining that - CastFromJS() failed, i.e. the native 'this' pointer for a bound - native T object could not be found. It uses TypeName::Value as the - class' name. - - This is primarily intended for use in two cases: - - - Internally in the cvv8 binding mechanisms. - - - In client code when binding non-member functions as JS-side methods of - native objects. - - Returns the result of v8::ThrowException(...). - - Example: - - @code - v8::Handle my_bound_func( v8::Arguments const & argv ) { - T * self = CastFromJS( argv.This() ); - if( ! self ) { - return TossMissingThis(); - } - ... - } - @endcode - - BUG: TypeName::Value is NOT used here because... If we instantiate - TypeName<> from here then we require a value for TypeName<>::Value or we - break FunctorTo and friends (because TypeName'ing functors isn't always - possible). The problem with that is that i want to use TypeName::Value's - address as a type key and that can't work cross-DLL on Windows (and - possibly other platforms) if we have a default value for TypeName::Value. - i hope to eventually find a solution which is both cross-platform and - allows us to invoke TypeName::Value from here. -*/ -template -v8::Handle TossMissingThis() -{ - return Toss(StringBuffer()<<"CastFromJS<" -#if 0 - <::Value -#else - <<'T' -#endif - <<">() returned NULL! Cannot find 'this' pointer!"); -} - -#if !defined(DOXYGEN) -namespace Detail { -/** Temporary internal macro. Undef'd at the end of this file. */ -#define HANDLE_PROPAGATE_EXCEPTION catch( MissingThisException const & ){ return TossMissingThis(); } \ - catch(...){ throw; } (void)0/* (void)0 is a hack to help emacs' indentation out!*/ - - /** - A MissingThisException type holding generic - message text which references TypeName::Value - as being the problematic class. - */ - template - struct MissingThisExceptionT : MissingThisException - { - MissingThisExceptionT() - { - this->init(); - } - }; - -/** - Temporary internal macro to trigger a static assertion if unlocking - support is requested but cannot be implemented for the given - wrapper due to constraints on our use of v8 when it is unlocked. - - This differs from ASSERT_UNLOCK_SANITY_CHECK in that this is intended - for use with functions which we _know_ (while coding, as opposed to - finding out at compile time) are not legally unlockable. -*/ -#define ASSERT_UNLOCKV8_IS_FALSE typedef char ThisSpecializationCannotUseV8Unlocker[!UnlockV8 ? 1 : -1] -/** - Temporary internal macro to trigger a static assertion if: - UnlockV8 is true and SignatureIsUnlockable::Value is false. - This is to prohibit that someone accidentally enables locking - when using a function type which we know (based on its - signature's types) cannot obey the (un)locking rules. -*/ -#define ASSERT_UNLOCK_SANITY_CHECK typedef char AssertCanEnableUnlock[ \ - !UnlockV8 ? 1 : (SignatureIsUnlockable< SignatureType >::Value ? 1 : -1) \ - ] - - template >::Value > - struct FunctionForwarder DOXYGEN_FWD_DECL_KLUDGE; - - template - struct FunctionForwarder - : FunctionSignature - { - public: - typedef FunctionSignature SignatureType; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - return (RV) func(argv); - } - - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return CastToJS( CallNative( func, argv ) ); - } - - ASSERT_UNLOCKV8_IS_FALSE; - typedef char AssertArity[ sl::Arity::Value == -1 ? 1 : -1]; - }; - - //! Reminder to self: we really do need this specialization for some cases. - template - struct FunctionForwarder - : FunctionForwarder - {}; - - template - struct FunctionForwarder<0,Sig, UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef typename SignatureType::ReturnType ReturnType; - typedef typename SignatureType::FunctionType FunctionType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & ) - { - V8Unlocker const & unlocker = ( V8Unlocker() ); - return func(); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return CastToJS( CallNative( func, argv ) ); - } - ASSERT_UNLOCK_SANITY_CHECK; - typedef char AssertArity[ sl::Arity::Value == 0 ? 1 : -1]; - }; - - template >::Value> - struct FunctionForwarderVoid DOXYGEN_FWD_DECL_KLUDGE; - - template - struct FunctionForwarderVoid<0,Sig, UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef typename SignatureType::ReturnType ReturnType; - typedef Sig FunctionType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & ) - { - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)func() - /* the explicit cast there is a workaround for the RV==void - case. It is a no-op for other cases, since the return value - is already RV. Some compilers (MSVC) don't allow an explicit - return of a void expression without the cast. - */; - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - CallNative( func, argv ); - return v8::Undefined(); - } - ASSERT_UNLOCK_SANITY_CHECK; - typedef char AssertArity[ sl::Arity::Value == 0 ? 1 : -1]; - }; - - template - struct FunctionForwarderVoid - : FunctionSignature - { - public: - typedef FunctionSignature SignatureType; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)func(argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - CallNative( func, argv ); - return v8::Undefined(); - } - ASSERT_UNLOCKV8_IS_FALSE; - typedef char AssertArity[ sl::Arity::Value == -1 ? 1 : -1]; - }; - - /** - Internal impl for cvv8::ConstMethodForwarder. - */ - template >::Value - > - struct MethodForwarder DOXYGEN_FWD_DECL_KLUDGE; - - - template - struct MethodForwarder : MethodSignature - { - public: - typedef MethodSignature SignatureType; - typedef typename SignatureType::ReturnType ReturnType; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename TypeInfo::Type Type; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (self.*func)(); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - return CastToJS( CallNative( self, func, argv ) ); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - return CastToJS( CallNative( func, argv ) ); - } - HANDLE_PROPAGATE_EXCEPTION; - } - - ASSERT_UNLOCK_SANITY_CHECK; - }; - - template - struct MethodForwarder - : MethodSignature - { - public: - typedef MethodSignature SignatureType; - typedef char AssertArity[ sl::Arity::Value == -1 ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - return (self.*func)(argv); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - return CastToJS( CallNative( self, func, argv ) ); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - return CastToJS( CallNative(func, argv) ); - } - HANDLE_PROPAGATE_EXCEPTION; - } - ASSERT_UNLOCKV8_IS_FALSE; - }; - - template - struct MethodForwarder : - MethodForwarder - {}; - - template >::Value - > - struct MethodForwarderVoid DOXYGEN_FWD_DECL_KLUDGE; - - template - struct MethodForwarderVoid - : MethodSignature - { - public: - typedef MethodSignature SignatureType; - typedef typename SignatureType::FunctionType FunctionType; - typedef T Type; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( Type & self, FunctionType func, v8::Arguments const & ) - { - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)(); - } - static v8::Handle Call( Type & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct MethodForwarderVoid - : MethodSignature - { - public: - typedef MethodSignature SignatureType; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename TypeInfo::Type Type; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( Type & self, FunctionType func, v8::Arguments const & argv ) - { - return (ReturnType)(self.*func)(argv); - } - static v8::Handle Call( Type & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - ASSERT_UNLOCKV8_IS_FALSE; - }; - - template - struct MethodForwarderVoid - : MethodForwarderVoid - {}; - - /** - Internal impl for cvv8::ConstMethodForwarder. - */ - template >::Value - > - struct ConstMethodForwarder DOXYGEN_FWD_DECL_KLUDGE; - - template - struct ConstMethodForwarder : ConstMethodSignature - { - public: - typedef ConstMethodSignature SignatureType; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & ) - { - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (self.*func)(); - } - - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - return CastToJS( CallNative( self, func, argv ) ); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - return CastToJS( CallNative(func, argv) ); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct ConstMethodForwarder - : ConstMethodSignature - { - public: - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ sl::Arity::Value == -1 ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - return (ReturnType)(self.*func)(argv); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - return CastToJS( CallNative( self, func, argv ) ); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - return CastToJS( CallNative(func, argv) ); - } - HANDLE_PROPAGATE_EXCEPTION; - } - ASSERT_UNLOCKV8_IS_FALSE; - }; - - template - struct ConstMethodForwarder - : ConstMethodForwarder - {}; - - template >::Value - > - struct ConstMethodForwarderVoid DOXYGEN_FWD_DECL_KLUDGE; - - template - struct ConstMethodForwarderVoid : ConstMethodSignature - { - public: - typedef ConstMethodSignature SignatureType; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - typedef typename TypeInfo::Type Type; - static ReturnType CallNative( Type const & self, FunctionType func, v8::Arguments const & ) - { - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)(); - } - - static v8::Handle Call( Type const & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - ASSERT_UNLOCK_SANITY_CHECK; - }; - - template - struct ConstMethodForwarderVoid - : ConstMethodSignature - { - public: - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ sl::Arity::Value == -1 ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - typedef typename TypeInfo::Type Type; - static ReturnType CallNative( Type const & self, FunctionType func, v8::Arguments const & argv ) - { - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)(); - } - static v8::Handle Call( Type const & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - return CastToJS( CallNative( func, argv ) ); - } - HANDLE_PROPAGATE_EXCEPTION; - } - ASSERT_UNLOCKV8_IS_FALSE; - }; - - template - struct ConstMethodForwarderVoid - : ConstMethodForwarderVoid - {}; - -} -#endif // DOXYGEN - -/** - A helper type for passing v8::Arguments lists to native non-member - functions. - - Sig must be a function-signature-like argument. e.g. , - and the members of this class expect functions matching that signature. - - If UnlockV8 is true then v8::Unlocker will be used to unlock v8 - for the duration of the call to Func(). HOWEVER... (the rest of - these docs are about the caveats)... - - A UnlockV8 value of SignatureIsUnlockable::Value uses a - reasonably sound heuristic but it cannot predict certain - app-dependent conditions which render its guess semantically - invalid. See SignatureIsUnlockable for more information. - - It is illegal for UnlockV8 to be true if ANY of the following - applies: - - - The callback itself will "use" v8 but does not explicitly use - v8::Locker. If it uses v8::Locker then it may safely enable - unlocking support. We cannot determine via templates whether - or not a function "uses" v8 except by guessing based on the - return and arguments types. - - - Any of the return or argument types for the function are v8 - types, e.g. v8::Handle or v8::Arguments. - SignatureIsUnlockable::Value will evaluate to false - if any of the "known bad" types is contained in the function's - signature. If this function is given a true value but - SignatureIsUnlockable::Value is false then - a compile-time assertion will be triggered. - - - Certain callback signatures cannot have unlocking support - enabled because if we unlock then we cannot legally access the data - we need to convert. These will cause a compile-time assertion - if UnlockV8 is true. All such bits are incidentally covered by - SignatureIsUnlockable's check, so this assertion can - only happen if the client explicitly sets UnlockV8 to true for - those few cases. - - - There might be other, as yet unknown/undocumented, corner cases - where unlocking v8 is semantically illegal at this level of the - API. - - Violating any of these leads to undefined behaviour. The library - tries to fail at compile time for invalid combinations when it - can, but (as described aboved) it can be fooled into thinking that - unlocking is safe. - - Reminder to self: we can implement this completely via inheritance of - the internal Proxy type, but i REALLY want the API docs out here at this - level instead of in the Detail namespace (which i filter out of doxygen - for the most part). -*/ -template >::Value -> -struct FunctionForwarder -{ -private: - typedef typename tmp::IfElse< tmp::SameType::ReturnType>::Value, - Detail::FunctionForwarderVoid< sl::Arity< Signature >::Value, Sig, UnlockV8 >, - Detail::FunctionForwarder< sl::Arity< Signature >::Value, Sig, UnlockV8 > - >::Type - Proxy; -public: - typedef typename Proxy::SignatureType SignatureType; - typedef typename Proxy::ReturnType ReturnType; - typedef typename Proxy::FunctionType FunctionType; - /** - Passes the given arguments to func(), converting them to the appropriate - types. If argv.Length() is less than sl::Arity< SignatureType >::Value then - a JS exception is thrown, with one exception: if the function has "-1 arity" - (i.e. it is InvocationCallback-like) then argv is passed on to it regardless - of the value of argv.Length(). - - The native return value of the call is returned to the caller. - */ - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - return Proxy::CallNative( func, argv ); - } - /** - Equivalent to CastToJS( CallNative(func,argv) ) unless ReturnType - is void, in which case CastToJS() is not invoked and v8::Undefined() - will be returned. - */ - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return Proxy::Call( func, argv ); - } -}; - -/** - CallForwarder basically does the opposite of FunctionForwarder: it - converts native arguments to JS and calls a JS function. - - The default implementation is useless - it must be specialized - for each arity. -*/ -template -struct CallForwarder -{ - /** - Implementations must be templates taking Arity arguments in addition - to the first two. All argument types must legal for use with - CastToJS(). - - If either self or func.IsEmpty() then a JS exception must be thrown, - else implementations must return func->Call(self, N, ARGS), where - ARGS is an array of v8::Handle and N is the number of - items in that array (and, not coincidentally, is the same value as - Arity). The ARGS array must be populated by calling CastToJS(ARG_N) - for each argument, where ARG_N is the Nth argument. - */ - static v8::Handle Call( v8::Handle const & self, - v8::Handle const & func, - ... ); - /** - Convenience form of Call() which must be equivalent to - Call(func,func,...). - */ - static v8::Handle Call( v8::Handle const & func, ... ); -}; - -//! Specialization for 0-arity calls. -template <> -struct CallForwarder<0> -{ - static v8::Handle Call( v8::Handle const & self, - v8::Handle const & func ) - { - return (self.IsEmpty() || func.IsEmpty()) - ? Toss("Illegal argument: empty v8::Handle<>.") - : func->Call(self, 0, NULL); - } - static v8::Handle Call( v8::Handle const & func ) - { - return Call( func, func ); - } -}; - - -#if !defined(DOXYGEN) -namespace Detail { - - /** - Base internal implementation of cvv8::FunctionToInCa. - */ - template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< FunctionSignature >::Value > - struct FunctionToInCa : FunctionPtr, InCa - { - - typedef FunctionSignature SignatureType; - typedef FunctionForwarder< sl::Arity::Value, Sig, UnlockV8 > Proxy; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( v8::Arguments const & argv ) - { - return (ReturnType)Proxy::CallNative( Func, argv ); - /** - The (ReturnType) cast is effectively a no-op for all types - except void, where it is used to get around a limitation in - some compilers which does not allow us to explicitly return - foo() when foo() returns void. - */ - } - static v8::Handle Call( v8::Arguments const & argv ) - { - return Proxy::Call( Func, argv ); - } - ASSERT_UNLOCK_SANITY_CHECK; - }; - - /** Almost identical to FunctionToInCa, but expressly does not - instantiate NativeToJS< Signature::ReturnType >, meaning - that: - - a) it can proxy functions which have non-convertible return types. - - b) JS always gets the 'undefined' JS value as the return value. - */ - template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< FunctionSignature >::Value > - struct FunctionToInCaVoid : FunctionPtr, InCa - { - typedef FunctionSignature SignatureType; - typedef FunctionForwarderVoid< sl::Arity::Value, Sig, UnlockV8 > Proxy; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( v8::Arguments const & argv ) - { - return (ReturnType)Proxy::CallNative( Func, argv ); - } - static v8::Handle Call( v8::Arguments const & argv ) - { - return Proxy::Call( Func, argv ); - } - ASSERT_UNLOCK_SANITY_CHECK; - }; - - /** Method equivalent to FunctionToInCa. */ - template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< MethodSignature >::Value - > - struct MethodToInCa : MethodPtr, InCa - { - typedef MethodPtr SignatureType; - enum { Arity = sl::Arity::Value }; - typedef MethodForwarder< T, Arity, Sig, UnlockV8 > Proxy; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, v8::Arguments const & argv ) - { - return Proxy::CallNative( self, Func, argv ); - } - static ReturnType CallNative( v8::Arguments const & argv ) - { - return Proxy::Call( Func, argv ); - } - static v8::Handle Call( v8::Arguments const & argv ) - { - return Proxy::Call( Func, argv ); - } - static v8::Handle Call( T & self, v8::Arguments const & argv ) - { - return Proxy::Call( self, Func, argv ); - } - ASSERT_UNLOCK_SANITY_CHECK; - }; - - /** Method equivalent to FunctionToInCaVoid. */ - template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< MethodSignature >::Value - > - struct MethodToInCaVoid : MethodPtr, InCa - { - typedef MethodPtr SignatureType; - enum { Arity = sl::Arity::Value }; - typedef MethodForwarderVoid< T, Arity, Sig, UnlockV8 > Proxy; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, v8::Arguments const & argv ) - { - return Proxy::CallNative( self, Func, argv ); - } - static ReturnType CallNative( v8::Arguments const & argv ) - { - return Proxy::Call( Func, argv ); - } - static v8::Handle Call( v8::Arguments const & argv ) - { - return Proxy::Call( Func, argv ); - } - static v8::Handle Call( T & self, v8::Arguments const & argv ) - { - return Proxy::Call( self, Func, argv ); - } - ASSERT_UNLOCK_SANITY_CHECK; - }; - - /** Const method equivalent to MethodToInCa. */ - template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< ConstMethodSignature >::Value - > - struct ConstMethodToInCa : ConstMethodPtr, InCa - { - typedef ConstMethodPtr SignatureType; - typedef ConstMethodForwarder< T, sl::Arity::Value, Sig, UnlockV8 > Proxy; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, v8::Arguments const & argv ) - { - return Proxy::CallNative( self, Func, argv ); - } - static ReturnType CallNative( v8::Arguments const & argv ) - { - return Proxy::Call( Func, argv ); - } - static v8::Handle Call( v8::Arguments const & argv ) - { - return Proxy::Call( Func, argv ); - } - static v8::Handle Call( T const & self, v8::Arguments const & argv ) - { - return Proxy::Call( self, Func, argv ); - } - }; - - template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< ConstMethodSignature >::Value - > - struct ConstMethodToInCaVoid : ConstMethodPtr, InCa - { - typedef ConstMethodPtr SignatureType; - typedef ConstMethodForwarderVoid< T, sl::Arity::Value, Sig, UnlockV8 > Proxy; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, v8::Arguments const & argv ) - { - return Proxy::CallNative( self, Func, argv ); - } - static ReturnType CallNative( v8::Arguments const & argv ) - { - return Proxy::Call( Func, argv ); - } - static v8::Handle Call( v8::Arguments const & argv ) - { - return Proxy::Call( Func, argv ); - } - static v8::Handle Call( T const & self, v8::Arguments const & argv ) - { - return Proxy::Call( self, Func, argv ); - } - ASSERT_UNLOCK_SANITY_CHECK; - }; - -} // Detail namespace -#endif // DOXYGEN -#undef ASSERT_UNLOCK_SANITY_CHECK -#undef ASSERT_UNLOCKV8_IS_FALSE - - -/** - A template for converting free (non-member) function pointers - to v8::InvocationCallback. - - Sig must be a function signature. Func must be a pointer to a function - with that signature. - - If UnlockV8 is true then v8::Unlocker will be used to unlock v8 - for the duration of the call to Func(). HOWEVER... see - FunctionForwarder for the details/caveats regarding that - parameter. - - Example: - - @code - v8::InvocationCallback cb = - FunctionToInCa< int (int), ::putchar>::Call; - @endcode -*/ -template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< Signature >::Value - > -struct FunctionToInCa - : tmp::IfElse< tmp::SameType::ReturnType>::Value, - Detail::FunctionToInCaVoid< Sig, Func, UnlockV8>, - Detail::FunctionToInCa< Sig, Func, UnlockV8> - >::Type -{}; - -/** - A variant of FunctionToInCa with the property of NOT invoking the - conversion of the function's return type from native to JS form. i.e. it - does not cause NativeToJS< Signature::ReturnType > to be - instantiated. This is useful when such a conversion is not legal because - CastToJS() won't work on it or, more generally, when you want the JS - interface to always get the undefined return value. - - Call() always returns v8::Undefined(). CallNative(), however, - returns the real return type specified by Sig (which may be void). - - Example: - - @code - v8::InvocationCallback cb = - FunctionToInCaVoid< int (int), ::putchar>::Call; - @endcode -*/ -template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< Signature >::Value - > -struct FunctionToInCaVoid : Detail::FunctionToInCaVoid< Sig, Func, UnlockV8> -{}; - - -/** - A template for converting non-const member function pointers to - v8::InvocationCallback. If T is const qualified then this works - as for ConstMethodToInCaVoid. - - To convert JS objects to native 'this' pointers this API uses - CastFromJS(arguments.This()), where arguments is the - v8::Arguments instance passed to the generated InvocationCallback - implementation. If that conversion fails then the generated - functions will throw a JS-side exception when called. - - T must be some client-specified type which is presumably bound (or - at least bindable) to JS-side Objects. Sig must be a member - function signature for T. Func must be a pointer to a function with - that signature. - - See FunctionForwarder for details about the UnlockV8 parameter. - - Example: - - @code - v8::InvocationCallback cb = - MethodToInCa::Call; - // For const methods: - cb = MethodToInCa::Call; - @endcode -*/ -template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< MethodSignature >::Value - > -struct MethodToInCa - : tmp::IfElse< tmp::SameType::ReturnType>::Value, - Detail::MethodToInCaVoid, - Detail::MethodToInCa - >::Type -{ -}; - -/** - See FunctionToInCaVoid - this is identical exception that it - works on member functions of T. If T is const qualified - then this works as for ConstMethodToInCaVoid. - - Example: - - @code - v8::InvocationCallback cb = - MethodToInCaVoid< T, int (int), &T::myFunc>::Call; - @endcode - -*/ -template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< MethodSignature >::Value - > -struct MethodToInCaVoid - : Detail::MethodToInCaVoid -{ -}; - -#if !defined(DOXYGEN) -namespace Detail { - template - struct FunctorToInCaSelector : ConstMethodForwarder >::Value, Sig, UnlockV8> - { - }; - template - struct FunctorToInCaSelector : ConstMethodForwarderVoid >::Value, Sig, UnlockV8> - {}; -} -#endif - -/** - This class converts a functor to an InvocationCallback. Ftor must - be a functor type. Sig must be a signature unambiguously matching - a Ftor::operator() implementation and Ftor::operator() must be - const. UnlockV8 is as described for FunctionToInCa. -*/ -template >::Value - > -struct FunctorToInCa : InCa -{ - inline static v8::Handle Call( v8::Arguments const & argv ) - { - typedef Detail::FunctorToInCaSelector< - typename Signature::ReturnType, Ftor, Sig, UnlockV8 - > Proxy; - return Proxy::Call( Ftor(), &Ftor::operator(), argv ); - } -}; - -/** - The functor equivalent of FunctionToInCaVoid. See FunctorToInCa for - the requirements of the Ftor and Sig types. -*/ -template >::Value - > -struct FunctorToInCaVoid : InCa -{ - inline static v8::Handle Call( v8::Arguments const & argv ) - { - typedef Detail::FunctorToInCaSelector< - void, Ftor, Sig, UnlockV8 - > Proxy; - return Proxy::Call( Ftor(), &Ftor::operator(), argv ); - } -}; - -/** - Functionally identical to MethodToInCa, but for const member functions. - - See FunctionForwarder for details about the UnlockV8 parameter. - - Note that the Sig signature must be suffixed with a const qualifier! - - Example: - - @code - v8::InvocationCallback cb = - ConstMethodToInCa< T, int (int), &T::myFunc>::Call; - @endcode - -*/ -template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< ConstMethodSignature >::Value - > -struct ConstMethodToInCa -#if 0 // not working due to an ambiguous Sig vs Sig. Kinda weird, since MethodToInCa works. - : MethodToInCa {}; -#else - : tmp::IfElse< tmp::SameType::ReturnType>::Value, - Detail::ConstMethodToInCaVoid, - Detail::ConstMethodToInCa - >::Type -{}; -#endif -/** - See FunctionToInCaVoid - this is identical exception that it - works on const member functions of T. - - Note that the Sig signature must be suffixed with a const qualifier! - - Example: - - @code - v8::InvocationCallback cb = - ConstMethodToInCaVoid< T, int (int), &T::myFunc>::Call; - @endcode - -*/ -template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< ConstMethodSignature >::Value - > -struct ConstMethodToInCaVoid : Detail::ConstMethodToInCaVoid -{}; - -/** - Identicial to FunctionForwarder, but works on non-const - member methods of type T. - - Sig must be a function-signature-like argument. e.g. , and the members of this class expect T member - functions matching that signature. -*/ -template >::Value> -struct MethodForwarder -{ -private: - typedef typename - tmp::IfElse< tmp::SameType::ReturnType>::Value, - Detail::MethodForwarderVoid< T, sl::Arity< Signature >::Value, Sig, UnlockV8 >, - Detail::MethodForwarder< T, sl::Arity< Signature >::Value, Sig, UnlockV8 > - >::Type - Proxy; -public: - typedef typename Proxy::SignatureType SignatureType; - typedef typename Proxy::FunctionType FunctionType; - typedef typename Proxy::ReturnType ReturnType; - /** - Passes the given arguments to (self.*func)(), converting them - to the appropriate types. If argv.Length() is less than - sl::Arity::Value then a JS exception is - thrown, with one exception: if the function has "-1 arity" - (i.e. it is InvocationCallback-like) then argv is passed on - to it regardless of the value of argv.Length(). - */ - inline static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - return Proxy::Call( self, func, argv ); - } - - /** - Like the 3-arg overload, but tries to extract the (T*) object using - CastFromJS(argv.This()). - */ - inline static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return Proxy::Call( func, argv ); - } -}; - - -/** - Identical to MethodForwarder, but works on const member methods. -*/ -template >::Value - > -struct ConstMethodForwarder -#if 1 //?msvc Seems to work. -: MethodForwarder {}; -#else -{ -private: - typedef typename - tmp::IfElse< tmp::SameType::ReturnType>::Value, - Detail::ConstMethodForwarderVoid< T, sl::Arity< Signature >::Value, Sig, UnlockV8 >, - Detail::ConstMethodForwarder< T, sl::Arity< Signature >::Value, Sig, UnlockV8 > - >::Type - Proxy; -public: - typedef typename Proxy::SignatureType SignatureType; - typedef typename Proxy::FunctionType FunctionType; - - /** - Passes the given arguments to (self.*func)(), converting them - to the appropriate types. If argv.Length() is less than - sl::Arity< Signature >::Value then a JS exception is thrown, with one - exception: if the function has "-1 arity" (i.e. it is - InvocationCallback-like) then argv is passed on to it - regardless of the value of argv.Length(). - */ - inline static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - return Proxy::Call( self, func, argv ); - } - - /** - Like the 3-arg overload, but tries to extract the (T const *) - object using CastFromJS(argv.This()). - */ - inline static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return Proxy::Call( func, argv ); - } -}; -#endif - -/** - Tries to forward the given arguments to the given native - function. Will fail if argv.Lengt() is not at least - sl::Arity>::Value, throwing a JS exception in that - case _unless_ the function is InvocationCallback-like, in which - case argv is passed directly to it regardless of the value of - argv.Length(). -*/ -template -inline typename FunctionSignature::ReturnType -forwardFunction( Sig func, v8::Arguments const & argv ) -{ - typedef FunctionSignature MSIG; - typedef typename MSIG::ReturnType RV; - enum { Arity = sl::Arity< Signature >::Value }; - typedef typename - tmp::IfElse< tmp::SameType::Value, - Detail::FunctionForwarderVoid< Arity, Sig >, - Detail::FunctionForwarder< Arity, Sig > - >::Type Proxy; - return (RV)Proxy::CallNative( func, argv ); -} - -/** - Works like forwardFunction(), but forwards to the - given non-const member function and treats the given object - as the 'this' pointer. -*/ -template -inline typename MethodSignature::ReturnType -forwardMethod( T & self, - Sig func, - /* if i do: typename MethodSignature::FunctionType - then this template is never selected. */ - v8::Arguments const & argv ) -{ - typedef MethodSignature MSIG; - typedef typename MSIG::ReturnType RV; - enum { Arity = sl::Arity< MSIG >::Value }; - typedef typename - tmp::IfElse< tmp::SameType::Value, - Detail::MethodForwarderVoid< T, Arity, Sig >, - Detail::MethodForwarder< T, Arity, Sig > - >::Type Proxy; - return (RV)Proxy::CallNative( self, func, argv ); -} - -/** - Like the 3-arg forwardMethod() overload, but - extracts the native T 'this' object from argv.This(). - - Note that this function requires that the caller specify - the T template parameter - it cannot deduce it. -*/ -template -inline typename MethodSignature::ReturnType -forwardMethod(Sig func, v8::Arguments const & argv ) -{ - typedef MethodSignature MSIG; - typedef typename MSIG::ReturnType RV; - enum { Arity = sl::Arity< MSIG >::Value }; - typedef typename - tmp::IfElse< tmp::SameType::Value, - Detail::MethodForwarderVoid< T, Arity, Sig >, - Detail::MethodForwarder< T, Arity, Sig > - >::Type Proxy; - return (RV)Proxy::CallNative( func, argv ); -} - - -/** - Works like forwardMethod(), but forwards to the given const member - function and treats the given object as the 'this' pointer. - -*/ -template -inline typename ConstMethodSignature::ReturnType -forwardConstMethod( T const & self, - //typename ConstMethodSignature::FunctionType func, - Sig func, - v8::Arguments const & argv ) -{ - typedef ConstMethodSignature MSIG; - typedef typename MSIG::ReturnType RV; - enum { Arity = sl::Arity< MSIG >::Value }; - typedef typename - tmp::IfElse< tmp::SameType::Value, - Detail::ConstMethodForwarderVoid< T, Arity, Sig >, - Detail::ConstMethodForwarder< T, Arity, Sig > - >::Type Proxy; - return (RV)Proxy::CallNative( self, func, argv ); -} - -/** - Like the 3-arg forwardConstMethod() overload, but - extracts the native T 'this' object from argv.This(). - - Note that this function requires that the caller specify - the T template parameter - it cannot deduce it. -*/ -template -inline typename ConstMethodSignature::ReturnType -forwardConstMethod(Sig func, v8::Arguments const & argv ) -{ - typedef ConstMethodSignature MSIG; - typedef typename MSIG::ReturnType RV; - enum { Arity = sl::Arity< MSIG >::Value }; - typedef typename - tmp::IfElse< tmp::SameType::Value, - Detail::ConstMethodForwarderVoid< T, Arity, Sig >, - Detail::ConstMethodForwarder< T, Arity, Sig > - >::Type Proxy; - return (RV)Proxy::CallNative( func, argv ); -} - -/** - A structified/functorified form of v8::InvocationCallback. It is - sometimes convenient to be able to use a typedef to create an alias - for a given InvocationCallback. Since we cannot typedef function - templates this way, this class can fill that gap. -*/ -template -struct InCaToInCa : FunctionToInCa< v8::Handle (v8::Arguments const &), ICB> -{ -}; - - -#if 0 // YAGNI -/** - "Converts" an InCaToInCa instance to JS by treating it as an - InvocationCallback function. This is primarily useful in - conjunction with ClassCreator::Set() to add function bindings. -*/ -template -struct NativeToJS< InCaToInCa > -{ - /** - Returns a JS handle to InCaToInCa::Call(). - */ - v8::Handle operator()( InCaToInCa const & ) - { - return v8::FunctionTemplate::New(InCaToInCa::Call)->GetFunction(); - } -}; -#endif - -#if !defined(DOXYGEN) -namespace Detail { - /** Internal code duplication reducer. */ - template - v8::Handle TossArgCountError( v8::Arguments const & args ) - { - return Toss((StringBuffer() - <<"Incorrect argument count ("< > -> -struct ArityDispatch : InCa -{ - /** - When called, if (Artity==-1) or if (Arity==args.Length()) then - InCaT::Call(args) is returned, else Fallback::Call(args) is returned. - - Implements the InvocationCallback interface. - */ - inline static v8::Handle Call( v8::Arguments const & args ) - { - return ( (-1==Arity) || (Arity == args.Length()) ) - ? InCaT::Call(args) - : Fallback::Call(args); - } -}; - - -/** - InvocationCallback wrapper which calls another InvocationCallback - and translates any native ExceptionT exceptions thrown by that - function into JS exceptions. - - ExceptionT must be an exception type which is thrown by const - reference (e.g. STL-style) as opposed to by pointer (MFC-style). - - SigGetMsg must be a function-signature-style argument describing - a method within ExceptionT which can be used to fetch the message - reported by the exception. It must meet these requirements: - - a) Be const - b) Take no arguments - c) Return a type convertible to JS via CastToJS() - - Getter must be a pointer to a function matching that signature. - - InCaT must be a InCa type. When Call() is called by v8, it will pass - on the call to InCaT::Call() and catch exceptions as described below. - - Exceptions of type (ExceptionT const &) and (ExceptionT const *) which - are thrown by ICB get translated into a JS exception with an error - message fetched using ExceptionT::Getter(). - - If PropagateOtherExceptions is true then exception of types other - than ExceptionT are re-thrown (which can be fatal to v8, so be - careful). If it is false then they are not propagated but the error - message in the generated JS exception is unspecified (because we - have no generic way to get such a message). If a client needs to - catch multiple exception types, enable propagation and chain the - callbacks together. In such a case, the outer-most (last) callback - in the chain should not propagate unknown exceptions (to avoid - killing v8). - - This type can be used to implement "chaining" of exception - catching, such that we can use the InCaCatcher - to catch various distinct exception types in the context - of one v8::InvocationCallback call. - - Example: - - @code - // Here we want to catch MyExceptionType, std::runtime_error, and - // std::exception (the base class of std::runtime_error, by the - // way) separately: - - // When catching within an exception hierarchy, start with the most - // specific (most-derived) exceptions. - - // Client-specified exception type: - typedef InCaCatcher< - MyExceptionType, - std::string (), - &MyExceptionType::getMessage, - InCaToInCa, // the "real" InvocationCallback - true // make sure propagation is turned on so chaining can work! - > Catch_MyEx; - - // std::runtime_error: - typedef InCaCatcher_std< Catch_MyEx, std::runtime_error > Catch_RTE; - - // std::exception: - typedef InCaCatcher_std< Catch_RTE > MyCatcher; - - // Now MyCatcher::Call is-a InvocationCallback which will handle - // MyExceptionType, std::runtime_error, and std::exception via - // different catch blocks. Note, however, that the visible - // behaviour for runtime_error and std::exception (its base class) - // will be identical here, though they actually have different - // code. - @endcode -*/ -template < typename ExceptionT, - typename SigGetMsg, - typename ConstMethodSignature::FunctionType Getter, - typename InCaT, - bool PropagateOtherExceptions = false - > -struct InCaCatcher : InCa -{ - /** - Returns ICB(args), converting any exceptions of type (ExceptionT - const &) or (ExceptionT const *) to JS exceptions. Other exception - types are handled as described in the class-level documentation. - - See the class-level docs for full details. - */ - static v8::Handle Call( v8::Arguments const & args ) - { - try - { - return InCaT::Call( args ); - } - catch( ExceptionT const & e2 ) - { - /* reminder to self: we now have the unusual corner case that - if Getter() returns a v8::Handle it will be thrown - as-is instead of wrapped in an Error object. See the Toss() docs - for why that is so. We could use tmp::SameType to alternately - call TossAsError(), but i'm too tired and i honestly don't ever - expect any exception type to return v8 handles. - */ - return Toss((e2.*Getter)()); - } - catch( ExceptionT const * e2 ) - { - return Toss((e2->*Getter)()); - } - catch(...) - { - if( PropagateOtherExceptions ) throw; - else return Toss("Unknown native exception thrown!"); - } - } -}; - -/** - Convenience form of InCaCatcher which catches std::exception objects and - uses their what() method to fetch the error message. - - The ConcreteException parameter may be std::exception (the default) or - any publically derived subclass of std::exception. When using a - non-default value, one can chain exception catchers to catch most-derived - types first. - - PropagateOtherExceptions determines whether _other_ exception types are - propagated or not. It defaults to false if ConcreteException is - std::exception (exactly, not a subtype), else it defaults to true. The - reasoning is: when chaining these handlers we need to catch the - most-derived first. Those handlers need to propagate other exceptions so - that we can catch the lesser-derived ones (or those from completely - different hierarchies) in subsequent catchers. The final catcher "should" - (arguably) swallow unknown exceptions, converting them to JS exceptions - with an unspecified message string (propagating them is technically legal - but will most likely crash v8). - - Here is an example of chaining: - - @code - typedef InCaCatcher_std< InCaToInCa, std::logic_error > LECatch; - typedef InCaCatcher_std< LECatch, std::runtime_error > RECatch; - typedef InCaCatcher_std< RECatch, std::bad_cast > BCCatch; - typedef InCaCatcher_std< BCCatch > BaseCatch; - v8::InvocationCallback cb = BaseCatch::Call; - @endcode - - In the above example any exceptions would be processed in the order: - logic_error, runtime_error, bad_cast, std::exception, anything else. Notice - that we took advantage of the PropagateOtherExceptions default value for all - cases to get the propagation behaviour we want. -*/ -template < - typename InCaT, - typename ConcreteException = std::exception, - bool PropagateOtherExceptions = !tmp::SameType< std::exception, ConcreteException >::Value -> -struct InCaCatcher_std : - InCaCatcher -{}; - -namespace Detail { - /** - An internal level of indirection for overloading-related - dispatchers. - */ - template - struct OverloadCallHelper : InCa - { - inline static v8::Handle Call( v8::Arguments const & argv ) - { - return InCaT::Call(argv); - } - }; - //! End-of-list specialization. - template <> - struct OverloadCallHelper : InCa - { - inline static v8::Handle Call( v8::Arguments const & argv ) - { - return Toss( StringBuffer() - << "End of typelist reached. Argument count=" - < Call( v8::Arguments const & argv ); - - And a static const integer (or enum) value called Arity, - which must specify the expected number of arguments, or be - negative specify that the function accepts any number of - arguments. - - In other words, all entries in FwdList must implement the - interface used by most of the InCa-related API. - - Example: - - @code - // Overload 3 variants of a member function: - typedef CVV8_TYPELIST(( - MethodToInCa, - MethodToInCa, - MethodToInCa - // Note that "N-arity" callbacks MUST come last in the list - // because they will always match any arity count and therefore - // trump any overloads which follow them. - )) OverloadList; - typedef ArityDispatchList< OverloadList > MyOverloads; - v8::InvocationCallback cb = MyOverloads::Call; - @endcode - - Note that only one line of that code is evaluated at runtime - the rest - is all done at compile-time. -*/ -template -struct ArityDispatchList : InCa -{ - /** - Tries to dispatch argv to one of the bound functions defined - in FwdList, based on the number of arguments in argv and - the Arity - - Implements the v8::InvocationCallback interface. - */ - inline static v8::Handle Call( v8::Arguments const & argv ) - { - typedef typename FwdList::Head FWD; - typedef typename FwdList::Tail Tail; - enum { Arity = sl::Arity< FWD >::Value }; - return ( (-1 == Arity) || (Arity == argv.Length()) ) - ? Detail::OverloadCallHelper::Call(argv) - : ArityDispatchList::Call(argv); - } -}; - -/** - End-of-list specialization. -*/ -template <> -struct ArityDispatchList : Detail::OverloadCallHelper -{ -}; - -#if !defined(DOXYGEN) -namespace Detail { - //! Internal helper for ToInCa impl. - template - struct ToInCaSigSelector : MethodSignature - { - template < typename MethodSignature::FunctionType Func, bool UnlockV8 > - struct Base : cvv8::MethodToInCa - { - }; - }; - - //! Internal helper for ToInCa impl. - template - struct ToInCaSigSelector : FunctionSignature - { - template < typename FunctionSignature::FunctionType Func, bool UnlockV8 > - struct Base : cvv8::FunctionToInCa - { - }; - }; - - //! Internal helper for ToInCaVoid impl. - template - struct ToInCaSigSelectorVoid : MethodSignature - { - template < typename MethodSignature::FunctionType Func, bool UnlockV8 > - struct Base : cvv8::MethodToInCaVoid - { - }; - }; - - //! Internal helper for ToInCaVoid impl. - template - struct ToInCaSigSelectorVoid : FunctionSignature - { - template < typename FunctionSignature::FunctionType Func, bool UnlockV8 > - struct Base : cvv8::FunctionToInCaVoid - { - }; - }; - -} -#endif // DOXYGEN - -/** - A wrapper for MethodToInCa, ConstMethodToInCa, and - FunctionToInCa, which determines which one of those to use based - on the type of T and its constness. - - For non-member functions, T must be void. For non-const member - functions T must be non-cvp-qualified T. For const member functions - T must be const-qualified. - - See FunctionForwarder for the meaning of the UnlockV8 parameter. - - Examples: - - @code - typedef ToInCa NonConstMethod; - typedef ToInCa ConstMethod; - typedef ToInCa Func; - - v8::InvocationCallback cb; - cb = NonConstMethod::Call; - cb = ConstMethod::Call; - cb = Func::Call; - @endcode - - Note the extra 'const' qualification for const method. This is - neccessary to be able to portably distinguish the constness - (some compilers allow us to add the const as part of the - function signature). Also note that the 'void' 1st parameter for - non-member functions is a bit of a hack. -*/ -template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< Detail::ToInCaSigSelector >::Value - > -struct ToInCa : Detail::ToInCaSigSelector::template Base -{ -}; - -/** - This works just like ToInCa but instead of behaving like - FunctionToInCa or Const/MethoToInCa it behaves like - FunctionToInCaVoid or Const/MethoToInCaVoid. -*/ -template ::FunctionType Func, - bool UnlockV8 = SignatureIsUnlockable< Detail::ToInCaSigSelector >::Value - > -struct ToInCaVoid : Detail::ToInCaSigSelectorVoid::template Base -{ -}; - - -/** - A slightly simplified form of FunctionToInCa which is only - useful for "InvocationCallback-like" functions and requires - only two arguments: - - @code - // int my_func( v8::Arguments const & ); - typedef InCaLikeFunction< int, my_func > F; - @endcode -*/ -template -struct InCaLikeFunction : FunctionToInCa< RV (v8::Arguments const &), Func> -{ -}; - -/** - A slightly simplified form of MethodToInCa which is only - useful for non-const "InvocationCallback-like" methods: - - @code - // Method: int MyType::func( v8::Arguments const & ) - typedef InCaLikeMethod F; - @endcode -*/ -template -struct InCaLikeMethod : MethodToInCa< T, RV (v8::Arguments const &), Func> -{}; - -/** - A slightly simplified form of ConstMethodToInCa which is only - useful for const "InvocationCallback-like" methods: - - @code - // Method: int MyType::func( v8::Arguments const & ) const - typedef InCaLikeConstMethod F; - @endcode -*/ -template -struct InCaLikeConstMethod : ConstMethodToInCa< T, RV (v8::Arguments const &), Func> -{}; - - -#if 0 -//! Don't use. Doesn't yet compile. Trying to consolidate Const/MethodXyz -template ::FunctionType Func> -struct SigToInCa : - tmp::IfElse< - sl::IsFunction< Signature >::Value, - FunctionToInCa< ASig, Func >, - typename tmp::IfElse< - sl::IsConstMethod< Signature >::Value, - ConstMethodToInCa< typename tmp::PlainType::Context>::Type, ASig, Func >, - MethodToInCa< typename Signature::Context, ASig, Func > - >::Type - >::Type -{}; -#endif - -/** - This class acts as a proxy for another InCa-compatible class, - running client-defined intialization code the _first_ time - its callback is called from JS. This could be used to run - library-dependent intialization routines such as lt_dlinit(). - - InCaT must conform to the InCa interface (i.e., have a static Call() - function which implements the v8::InvocationCallback interface). - - InitFunctor must be default-constructable and have an operator() - (preferably const) taking no args and returning any type which can be - ignored (i.e. not dynamically-allocated resources). -*/ -template -struct OneTimeInitInCa : InCa -{ - /** - The first time this function is called it runs - InitFunctor()() to execute any client-dependent setup. If - that throws a native exception it is propagated back to the - caller and initialization is considered NOT to have - occurred, meaning the next call to this function will also - run InitFunctor()(). - - If initialization does not throw, InCaT::Call(argv) is - called and its value is returned. Once initialization - succeeds, it is _not_ triggered on subsequent calls to this - function. - - Pedantic note: if this class is used in code which is linked - in from multiple DLLs, the init routine might be called - more than once, depending on the platform. - */ - static v8::Handle Call( v8::Arguments const & argv ) - { - static bool bob = false; - if( ! bob ) - { - InitFunctor()(); - /* Reminder: if it throws we do not set bob=true. - This is part of the interface, not an accident. - */ - bob = true; - } - return InCaT::Call( argv ); - } -}; - - -#if 0// i'm not yet decided on these bits... -struct NativeToJS_InCa_Base -{ - typedef v8::InvocationCallback ArgType; - template - inline v8::Handle operator()( SigT const & ) const - { - return v8::FunctionTemplate::New(SigT::Call)->GetFunction(); - } -}; - -template ::FunctionType Func> -struct NativeToJS< FunctionToInCa > : NativeToJS_InCa_Base {}; -template ::FunctionType Func> -struct NativeToJS< FunctionToInCaVoid > : NativeToJS_InCa_Base {}; - -template ::FunctionType Func> -struct NativeToJS< MethodToInCa > : NativeToJS_InCa_Base {}; -template ::FunctionType Func> -struct NativeToJS< MethodToInCaVoid > : NativeToJS_InCa_Base {}; - -template ::FunctionType Func> -struct NativeToJS< ConstMethodToInCa > : NativeToJS_InCa_Base {}; -template ::FunctionType Func> -struct NativeToJS< ConstMethodToInCaVoid > : NativeToJS_InCa_Base {}; - -template ::FunctionType Func> -struct NativeToJS< ToInCa > : NativeToJS_InCa_Base {}; -template ::FunctionType Func> -struct NativeToJS< ToInCaVoid > : NativeToJS_InCa_Base {}; -#endif - -#include "invocable_generated.hpp" -} // namespace - -#undef HANDLE_PROPAGATE_EXCEPTION -#undef ENABLE_TOINCA - -#endif /* CODE_GOOGLE_COM_V8_CONVERT_INVOCABLE_V8_HPP_INCLUDED */ diff --git a/vendor/libv8-convert/cvv8/detail/invocable_generated.hpp b/vendor/libv8-convert/cvv8/detail/invocable_generated.hpp deleted file mode 100644 index 6c7227f5f..000000000 --- a/vendor/libv8-convert/cvv8/detail/invocable_generated.hpp +++ /dev/null @@ -1,3588 +0,0 @@ -/* AUTO-GENERATED CODE! EDIT AT YOUR OWN RISK! */ -#if !defined(DOXYGEN) -namespace Detail { - template - struct FunctionForwarder<1,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (1 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - - typedef ArgCaster AC0; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return CastToJS( CallNative( func, argv ) ); - } - }; - - template - struct FunctionForwarderVoid<1,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (1 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - - typedef ArgCaster AC0; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - CallNative( func, argv ); - return v8::Undefined(); - } - }; -} -namespace Detail { - template - struct MethodForwarder : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (1 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - - typedef ArgCaster AC0; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct MethodForwarderVoid : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (1 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - - typedef ArgCaster AC0; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -namespace Detail { - template - struct ConstMethodForwarder : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (1 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - - typedef ArgCaster AC0; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct ConstMethodForwarderVoid : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (1 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - - typedef ArgCaster AC0; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -//! Specialization for 1-arity calls. -template <> -struct CallForwarder<1> -{ - template < typename A0> - static v8::Handle Call( v8::Handle const & self, - v8::Handle const & func, - A0 a0 - ) - { - v8::Handle args[] = { - CastToJS(a0) - }; - return (self.IsEmpty() || func.IsEmpty()) - ? Toss("Illegal argument: empty v8::Handle<>.") - : func->Call(self, sizeof(args)/sizeof(args[0]), args); - } - template < typename A0> - static v8::Handle Call( v8::Handle const & func, - A0 a0 - ) - { - return Call( func, func, a0 ); - } - -}; -namespace Detail { -template -struct CtorForwarderProxy -{ - enum { Arity = 1 }; - typedef typename Signature::ReturnType ReturnType; - static ReturnType Call( v8::Arguments const & argv ) - { - if( argv.Length() < Arity ) - { - throw std::range_error("CtorForwarder::Ctor() expects at least 1 JS arguments!"); - } - else - { - typedef typename sl::At< 0, Signature >::Type A0; - - typedef ArgCaster AC0; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - - typedef typename TypeInfo::Type Type; - return new Type( arg0 ); - } - } -}; -} -namespace Detail { - template - struct FunctionForwarder<2,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (2 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return CastToJS( CallNative( func, argv ) ); - } - }; - - template - struct FunctionForwarderVoid<2,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (2 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - CallNative( func, argv ); - return v8::Undefined(); - } - }; -} -namespace Detail { - template - struct MethodForwarder : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (2 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct MethodForwarderVoid : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (2 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -namespace Detail { - template - struct ConstMethodForwarder : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (2 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct ConstMethodForwarderVoid : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (2 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -//! Specialization for 2-arity calls. -template <> -struct CallForwarder<2> -{ - template < typename A0, typename A1> - static v8::Handle Call( v8::Handle const & self, - v8::Handle const & func, - A0 a0, A1 a1 - ) - { - v8::Handle args[] = { - CastToJS(a0), CastToJS(a1) - }; - return (self.IsEmpty() || func.IsEmpty()) - ? Toss("Illegal argument: empty v8::Handle<>.") - : func->Call(self, sizeof(args)/sizeof(args[0]), args); - } - template < typename A0, typename A1> - static v8::Handle Call( v8::Handle const & func, - A0 a0, A1 a1 - ) - { - return Call( func, func, a0,a1 ); - } - -}; -namespace Detail { -template -struct CtorForwarderProxy -{ - enum { Arity = 2 }; - typedef typename Signature::ReturnType ReturnType; - static ReturnType Call( v8::Arguments const & argv ) - { - if( argv.Length() < Arity ) - { - throw std::range_error("CtorForwarder::Ctor() expects at least 2 JS arguments!"); - } - else - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - - typedef typename TypeInfo::Type Type; - return new Type( arg0, arg1 ); - } - } -}; -} -namespace Detail { - template - struct FunctionForwarder<3,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (3 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return CastToJS( CallNative( func, argv ) ); - } - }; - - template - struct FunctionForwarderVoid<3,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (3 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - CallNative( func, argv ); - return v8::Undefined(); - } - }; -} -namespace Detail { - template - struct MethodForwarder : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (3 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct MethodForwarderVoid : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (3 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -namespace Detail { - template - struct ConstMethodForwarder : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (3 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct ConstMethodForwarderVoid : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (3 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -//! Specialization for 3-arity calls. -template <> -struct CallForwarder<3> -{ - template < typename A0, typename A1, typename A2> - static v8::Handle Call( v8::Handle const & self, - v8::Handle const & func, - A0 a0, A1 a1, A2 a2 - ) - { - v8::Handle args[] = { - CastToJS(a0), CastToJS(a1), CastToJS(a2) - }; - return (self.IsEmpty() || func.IsEmpty()) - ? Toss("Illegal argument: empty v8::Handle<>.") - : func->Call(self, sizeof(args)/sizeof(args[0]), args); - } - template < typename A0, typename A1, typename A2> - static v8::Handle Call( v8::Handle const & func, - A0 a0, A1 a1, A2 a2 - ) - { - return Call( func, func, a0,a1,a2 ); - } - -}; -namespace Detail { -template -struct CtorForwarderProxy -{ - enum { Arity = 3 }; - typedef typename Signature::ReturnType ReturnType; - static ReturnType Call( v8::Arguments const & argv ) - { - if( argv.Length() < Arity ) - { - throw std::range_error("CtorForwarder::Ctor() expects at least 3 JS arguments!"); - } - else - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - - typedef typename TypeInfo::Type Type; - return new Type( arg0, arg1, arg2 ); - } - } -}; -} -namespace Detail { - template - struct FunctionForwarder<4,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (4 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2, arg3 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return CastToJS( CallNative( func, argv ) ); - } - }; - - template - struct FunctionForwarderVoid<4,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (4 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2, arg3 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - CallNative( func, argv ); - return v8::Undefined(); - } - }; -} -namespace Detail { - template - struct MethodForwarder : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (4 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct MethodForwarderVoid : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (4 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -namespace Detail { - template - struct ConstMethodForwarder : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (4 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct ConstMethodForwarderVoid : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (4 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -//! Specialization for 4-arity calls. -template <> -struct CallForwarder<4> -{ - template < typename A0, typename A1, typename A2, typename A3> - static v8::Handle Call( v8::Handle const & self, - v8::Handle const & func, - A0 a0, A1 a1, A2 a2, A3 a3 - ) - { - v8::Handle args[] = { - CastToJS(a0), CastToJS(a1), CastToJS(a2), CastToJS(a3) - }; - return (self.IsEmpty() || func.IsEmpty()) - ? Toss("Illegal argument: empty v8::Handle<>.") - : func->Call(self, sizeof(args)/sizeof(args[0]), args); - } - template < typename A0, typename A1, typename A2, typename A3> - static v8::Handle Call( v8::Handle const & func, - A0 a0, A1 a1, A2 a2, A3 a3 - ) - { - return Call( func, func, a0,a1,a2,a3 ); - } - -}; -namespace Detail { -template -struct CtorForwarderProxy -{ - enum { Arity = 4 }; - typedef typename Signature::ReturnType ReturnType; - static ReturnType Call( v8::Arguments const & argv ) - { - if( argv.Length() < Arity ) - { - throw std::range_error("CtorForwarder::Ctor() expects at least 4 JS arguments!"); - } - else - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - - typedef typename TypeInfo::Type Type; - return new Type( arg0, arg1, arg2, arg3 ); - } - } -}; -} -namespace Detail { - template - struct FunctionForwarder<5,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (5 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2, arg3, arg4 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return CastToJS( CallNative( func, argv ) ); - } - }; - - template - struct FunctionForwarderVoid<5,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (5 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2, arg3, arg4 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - CallNative( func, argv ); - return v8::Undefined(); - } - }; -} -namespace Detail { - template - struct MethodForwarder : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (5 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct MethodForwarderVoid : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (5 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -namespace Detail { - template - struct ConstMethodForwarder : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (5 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct ConstMethodForwarderVoid : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (5 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -//! Specialization for 5-arity calls. -template <> -struct CallForwarder<5> -{ - template < typename A0, typename A1, typename A2, typename A3, typename A4> - static v8::Handle Call( v8::Handle const & self, - v8::Handle const & func, - A0 a0, A1 a1, A2 a2, A3 a3, A4 a4 - ) - { - v8::Handle args[] = { - CastToJS(a0), CastToJS(a1), CastToJS(a2), CastToJS(a3), CastToJS(a4) - }; - return (self.IsEmpty() || func.IsEmpty()) - ? Toss("Illegal argument: empty v8::Handle<>.") - : func->Call(self, sizeof(args)/sizeof(args[0]), args); - } - template < typename A0, typename A1, typename A2, typename A3, typename A4> - static v8::Handle Call( v8::Handle const & func, - A0 a0, A1 a1, A2 a2, A3 a3, A4 a4 - ) - { - return Call( func, func, a0,a1,a2,a3,a4 ); - } - -}; -namespace Detail { -template -struct CtorForwarderProxy -{ - enum { Arity = 5 }; - typedef typename Signature::ReturnType ReturnType; - static ReturnType Call( v8::Arguments const & argv ) - { - if( argv.Length() < Arity ) - { - throw std::range_error("CtorForwarder::Ctor() expects at least 5 JS arguments!"); - } - else - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - - typedef typename TypeInfo::Type Type; - return new Type( arg0, arg1, arg2, arg3, arg4 ); - } - } -}; -} -namespace Detail { - template - struct FunctionForwarder<6,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (6 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2, arg3, arg4, arg5 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return CastToJS( CallNative( func, argv ) ); - } - }; - - template - struct FunctionForwarderVoid<6,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (6 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2, arg3, arg4, arg5 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - CallNative( func, argv ); - return v8::Undefined(); - } - }; -} -namespace Detail { - template - struct MethodForwarder : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (6 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct MethodForwarderVoid : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (6 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -namespace Detail { - template - struct ConstMethodForwarder : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (6 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct ConstMethodForwarderVoid : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (6 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -//! Specialization for 6-arity calls. -template <> -struct CallForwarder<6> -{ - template < typename A0, typename A1, typename A2, typename A3, typename A4, typename A5> - static v8::Handle Call( v8::Handle const & self, - v8::Handle const & func, - A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5 - ) - { - v8::Handle args[] = { - CastToJS(a0), CastToJS(a1), CastToJS(a2), CastToJS(a3), CastToJS(a4), CastToJS(a5) - }; - return (self.IsEmpty() || func.IsEmpty()) - ? Toss("Illegal argument: empty v8::Handle<>.") - : func->Call(self, sizeof(args)/sizeof(args[0]), args); - } - template < typename A0, typename A1, typename A2, typename A3, typename A4, typename A5> - static v8::Handle Call( v8::Handle const & func, - A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5 - ) - { - return Call( func, func, a0,a1,a2,a3,a4,a5 ); - } - -}; -namespace Detail { -template -struct CtorForwarderProxy -{ - enum { Arity = 6 }; - typedef typename Signature::ReturnType ReturnType; - static ReturnType Call( v8::Arguments const & argv ) - { - if( argv.Length() < Arity ) - { - throw std::range_error("CtorForwarder::Ctor() expects at least 6 JS arguments!"); - } - else - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - - typedef typename TypeInfo::Type Type; - return new Type( arg0, arg1, arg2, arg3, arg4, arg5 ); - } - } -}; -} -namespace Detail { - template - struct FunctionForwarder<7,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (7 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return CastToJS( CallNative( func, argv ) ); - } - }; - - template - struct FunctionForwarderVoid<7,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (7 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - CallNative( func, argv ); - return v8::Undefined(); - } - }; -} -namespace Detail { - template - struct MethodForwarder : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (7 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct MethodForwarderVoid : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (7 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -namespace Detail { - template - struct ConstMethodForwarder : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (7 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct ConstMethodForwarderVoid : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (7 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -//! Specialization for 7-arity calls. -template <> -struct CallForwarder<7> -{ - template < typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6> - static v8::Handle Call( v8::Handle const & self, - v8::Handle const & func, - A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6 - ) - { - v8::Handle args[] = { - CastToJS(a0), CastToJS(a1), CastToJS(a2), CastToJS(a3), CastToJS(a4), CastToJS(a5), CastToJS(a6) - }; - return (self.IsEmpty() || func.IsEmpty()) - ? Toss("Illegal argument: empty v8::Handle<>.") - : func->Call(self, sizeof(args)/sizeof(args[0]), args); - } - template < typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6> - static v8::Handle Call( v8::Handle const & func, - A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6 - ) - { - return Call( func, func, a0,a1,a2,a3,a4,a5,a6 ); - } - -}; -namespace Detail { -template -struct CtorForwarderProxy -{ - enum { Arity = 7 }; - typedef typename Signature::ReturnType ReturnType; - static ReturnType Call( v8::Arguments const & argv ) - { - if( argv.Length() < Arity ) - { - throw std::range_error("CtorForwarder::Ctor() expects at least 7 JS arguments!"); - } - else - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - - typedef typename TypeInfo::Type Type; - return new Type( arg0, arg1, arg2, arg3, arg4, arg5, arg6 ); - } - } -}; -} -namespace Detail { - template - struct FunctionForwarder<8,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (8 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return CastToJS( CallNative( func, argv ) ); - } - }; - - template - struct FunctionForwarderVoid<8,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (8 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - CallNative( func, argv ); - return v8::Undefined(); - } - }; -} -namespace Detail { - template - struct MethodForwarder : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (8 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct MethodForwarderVoid : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (8 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -namespace Detail { - template - struct ConstMethodForwarder : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (8 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct ConstMethodForwarderVoid : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (8 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -//! Specialization for 8-arity calls. -template <> -struct CallForwarder<8> -{ - template < typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7> - static v8::Handle Call( v8::Handle const & self, - v8::Handle const & func, - A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7 - ) - { - v8::Handle args[] = { - CastToJS(a0), CastToJS(a1), CastToJS(a2), CastToJS(a3), CastToJS(a4), CastToJS(a5), CastToJS(a6), CastToJS(a7) - }; - return (self.IsEmpty() || func.IsEmpty()) - ? Toss("Illegal argument: empty v8::Handle<>.") - : func->Call(self, sizeof(args)/sizeof(args[0]), args); - } - template < typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7> - static v8::Handle Call( v8::Handle const & func, - A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7 - ) - { - return Call( func, func, a0,a1,a2,a3,a4,a5,a6,a7 ); - } - -}; -namespace Detail { -template -struct CtorForwarderProxy -{ - enum { Arity = 8 }; - typedef typename Signature::ReturnType ReturnType; - static ReturnType Call( v8::Arguments const & argv ) - { - if( argv.Length() < Arity ) - { - throw std::range_error("CtorForwarder::Ctor() expects at least 8 JS arguments!"); - } - else - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - - typedef typename TypeInfo::Type Type; - return new Type( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 ); - } - } -}; -} -namespace Detail { - template - struct FunctionForwarder<9,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (9 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - typedef typename sl::At< 8, Signature >::Type A8; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - typedef ArgCaster AC8; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - AC8 ac8; A8 arg8(ac8.ToNative(argv[8])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return CastToJS( CallNative( func, argv ) ); - } - }; - - template - struct FunctionForwarderVoid<9,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (9 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - typedef typename sl::At< 8, Signature >::Type A8; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - typedef ArgCaster AC8; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - AC8 ac8; A8 arg8(ac8.ToNative(argv[8])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - CallNative( func, argv ); - return v8::Undefined(); - } - }; -} -namespace Detail { - template - struct MethodForwarder : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (9 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - typedef typename sl::At< 8, Signature >::Type A8; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - typedef ArgCaster AC8; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - AC8 ac8; A8 arg8(ac8.ToNative(argv[8])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct MethodForwarderVoid : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (9 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - typedef typename sl::At< 8, Signature >::Type A8; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - typedef ArgCaster AC8; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - AC8 ac8; A8 arg8(ac8.ToNative(argv[8])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -namespace Detail { - template - struct ConstMethodForwarder : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (9 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - typedef typename sl::At< 8, Signature >::Type A8; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - typedef ArgCaster AC8; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - AC8 ac8; A8 arg8(ac8.ToNative(argv[8])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct ConstMethodForwarderVoid : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (9 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - typedef typename sl::At< 8, Signature >::Type A8; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - typedef ArgCaster AC8; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - AC8 ac8; A8 arg8(ac8.ToNative(argv[8])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -//! Specialization for 9-arity calls. -template <> -struct CallForwarder<9> -{ - template < typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8> - static v8::Handle Call( v8::Handle const & self, - v8::Handle const & func, - A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8 - ) - { - v8::Handle args[] = { - CastToJS(a0), CastToJS(a1), CastToJS(a2), CastToJS(a3), CastToJS(a4), CastToJS(a5), CastToJS(a6), CastToJS(a7), CastToJS(a8) - }; - return (self.IsEmpty() || func.IsEmpty()) - ? Toss("Illegal argument: empty v8::Handle<>.") - : func->Call(self, sizeof(args)/sizeof(args[0]), args); - } - template < typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8> - static v8::Handle Call( v8::Handle const & func, - A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8 - ) - { - return Call( func, func, a0,a1,a2,a3,a4,a5,a6,a7,a8 ); - } - -}; -namespace Detail { -template -struct CtorForwarderProxy -{ - enum { Arity = 9 }; - typedef typename Signature::ReturnType ReturnType; - static ReturnType Call( v8::Arguments const & argv ) - { - if( argv.Length() < Arity ) - { - throw std::range_error("CtorForwarder::Ctor() expects at least 9 JS arguments!"); - } - else - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - typedef typename sl::At< 8, Signature >::Type A8; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - typedef ArgCaster AC8; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - AC8 ac8; A8 arg8(ac8.ToNative(argv[8])); - - typedef typename TypeInfo::Type Type; - return new Type( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 ); - } - } -}; -} -namespace Detail { - template - struct FunctionForwarder<10,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (10 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - typedef typename sl::At< 8, Signature >::Type A8; - typedef typename sl::At< 9, Signature >::Type A9; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - typedef ArgCaster AC8; - typedef ArgCaster AC9; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - AC8 ac8; A8 arg8(ac8.ToNative(argv[8])); - AC9 ac9; A9 arg9(ac9.ToNative(argv[9])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - return CastToJS( CallNative( func, argv ) ); - } - }; - - template - struct FunctionForwarderVoid<10,Sig,UnlockV8> : FunctionSignature - { - typedef FunctionSignature SignatureType; - typedef char AssertArity[ (10 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - typedef typename sl::At< 8, Signature >::Type A8; - typedef typename sl::At< 9, Signature >::Type A9; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - typedef ArgCaster AC8; - typedef ArgCaster AC9; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - AC8 ac8; A8 arg8(ac8.ToNative(argv[8])); - AC9 ac9; A9 arg9(ac9.ToNative(argv[9])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 ); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - CallNative( func, argv ); - return v8::Undefined(); - } - }; -} -namespace Detail { - template - struct MethodForwarder : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (10 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - typedef typename sl::At< 8, Signature >::Type A8; - typedef typename sl::At< 9, Signature >::Type A9; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - typedef ArgCaster AC8; - typedef ArgCaster AC9; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - AC8 ac8; A8 arg8(ac8.ToNative(argv[8])); - AC9 ac9; A9 arg9(ac9.ToNative(argv[9])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct MethodForwarderVoid : MethodSignature - { - typedef MethodSignature SignatureType; - typedef char AssertArity[ (10 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - typedef typename sl::At< 8, Signature >::Type A8; - typedef typename sl::At< 9, Signature >::Type A9; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - typedef ArgCaster AC8; - typedef ArgCaster AC9; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - AC8 ac8; A8 arg8(ac8.ToNative(argv[8])); - AC9 ac9; A9 arg9(ac9.ToNative(argv[9])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 ); - } - static v8::Handle Call( T & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -namespace Detail { - template - struct ConstMethodForwarder : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (10 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - typedef typename sl::At< 8, Signature >::Type A8; - typedef typename sl::At< 9, Signature >::Type A9; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - typedef ArgCaster AC8; - typedef ArgCaster AC9; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - AC8 ac8; A8 arg8(ac8.ToNative(argv[8])); - AC9 ac9; A9 arg9(ac9.ToNative(argv[9])); - - V8Unlocker const & unlocker = ( V8Unlocker() ); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative( self, func, argv ) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try { return CastToJS( CallNative(func, argv) ); } - HANDLE_PROPAGATE_EXCEPTION; - } - }; - - template - struct ConstMethodForwarderVoid : ConstMethodSignature - { - typedef ConstMethodSignature SignatureType; - typedef char AssertArity[ (10 == sl::Arity::Value) ? 1 : -1]; - typedef typename SignatureType::FunctionType FunctionType; - typedef typename SignatureType::ReturnType ReturnType; - static ReturnType CallNative( T const & self, FunctionType func, v8::Arguments const & argv ) - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - typedef typename sl::At< 8, Signature >::Type A8; - typedef typename sl::At< 9, Signature >::Type A9; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - typedef ArgCaster AC8; - typedef ArgCaster AC9; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - AC8 ac8; A8 arg8(ac8.ToNative(argv[8])); - AC9 ac9; A9 arg9(ac9.ToNative(argv[9])); - - V8Unlocker const & unlocker = V8Unlocker(); - return (ReturnType)(self.*func)( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 ); - } - static v8::Handle Call( T const & self, FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative( self, func, argv ); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - static ReturnType CallNative( FunctionType func, v8::Arguments const & argv ) - { - T const * self = CastFromJS(argv.This()); - if( ! self ) throw MissingThisExceptionT(); - return (ReturnType)CallNative(*self, func, argv); - } - static v8::Handle Call( FunctionType func, v8::Arguments const & argv ) - { - try - { - CallNative(func, argv); - return v8::Undefined(); - } - HANDLE_PROPAGATE_EXCEPTION; - } - }; -} -//! Specialization for 10-arity calls. -template <> -struct CallForwarder<10> -{ - template < typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9> - static v8::Handle Call( v8::Handle const & self, - v8::Handle const & func, - A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9 - ) - { - v8::Handle args[] = { - CastToJS(a0), CastToJS(a1), CastToJS(a2), CastToJS(a3), CastToJS(a4), CastToJS(a5), CastToJS(a6), CastToJS(a7), CastToJS(a8), CastToJS(a9) - }; - return (self.IsEmpty() || func.IsEmpty()) - ? Toss("Illegal argument: empty v8::Handle<>.") - : func->Call(self, sizeof(args)/sizeof(args[0]), args); - } - template < typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9> - static v8::Handle Call( v8::Handle const & func, - A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9 - ) - { - return Call( func, func, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9 ); - } - -}; -namespace Detail { -template -struct CtorForwarderProxy -{ - enum { Arity = 10 }; - typedef typename Signature::ReturnType ReturnType; - static ReturnType Call( v8::Arguments const & argv ) - { - if( argv.Length() < Arity ) - { - throw std::range_error("CtorForwarder::Ctor() expects at least 10 JS arguments!"); - } - else - { - typedef typename sl::At< 0, Signature >::Type A0; - typedef typename sl::At< 1, Signature >::Type A1; - typedef typename sl::At< 2, Signature >::Type A2; - typedef typename sl::At< 3, Signature >::Type A3; - typedef typename sl::At< 4, Signature >::Type A4; - typedef typename sl::At< 5, Signature >::Type A5; - typedef typename sl::At< 6, Signature >::Type A6; - typedef typename sl::At< 7, Signature >::Type A7; - typedef typename sl::At< 8, Signature >::Type A8; - typedef typename sl::At< 9, Signature >::Type A9; - - typedef ArgCaster AC0; - typedef ArgCaster AC1; - typedef ArgCaster AC2; - typedef ArgCaster AC3; - typedef ArgCaster AC4; - typedef ArgCaster AC5; - typedef ArgCaster AC6; - typedef ArgCaster AC7; - typedef ArgCaster AC8; - typedef ArgCaster AC9; - - AC0 ac0; A0 arg0(ac0.ToNative(argv[0])); - AC1 ac1; A1 arg1(ac1.ToNative(argv[1])); - AC2 ac2; A2 arg2(ac2.ToNative(argv[2])); - AC3 ac3; A3 arg3(ac3.ToNative(argv[3])); - AC4 ac4; A4 arg4(ac4.ToNative(argv[4])); - AC5 ac5; A5 arg5(ac5.ToNative(argv[5])); - AC6 ac6; A6 arg6(ac6.ToNative(argv[6])); - AC7 ac7; A7 arg7(ac7.ToNative(argv[7])); - AC8 ac8; A8 arg8(ac8.ToNative(argv[8])); - AC9 ac9; A9 arg9(ac9.ToNative(argv[9])); - - typedef typename TypeInfo::Type Type; - return new Type( arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 ); - } - } -}; -} -#endif // if !defined(DOXYGEN) diff --git a/vendor/libv8-convert/cvv8/detail/signature_core.hpp b/vendor/libv8-convert/cvv8/detail/signature_core.hpp deleted file mode 100644 index b4ff3fe6d..000000000 --- a/vendor/libv8-convert/cvv8/detail/signature_core.hpp +++ /dev/null @@ -1,498 +0,0 @@ -#if !defined(CODE_GOOGLE_COM_V8_CONVERT_SIGNATURE_CORE_HPP_INCLUDED) -#define CODE_GOOGLE_COM_V8_CONVERT_SIGNATURE_CORE_HPP_INCLUDED 1 -#include "tmp.hpp" -#include "doxygen_hack.hpp" - -namespace cvv8 { -/** @file signature_core.hpp - -This file houses the core-most templates related to handling -function/method signatures as full-fleged types. -*/ - - - -/** @class Signature - - Base (unimplemented) template for holding function-signature-style - argument lists in a type-rich manner. Most implementations are - script-generated and accept up to some library-build-time-defined number - of types in their argument list (the interface guarantees at least 10 - unless the client builds a custom copy with a smaller limit). - - All specializations implement a "type list" interface. The sl namespace - contains several different compile-time algorithms (sometimes called - template metafunctions) for querying the arity and types in a signature. - - Sig must be a function-signature-style parameter list, e.g.: - - @code - Signature< void (int, double) > - Signature< void (MyType::*)( int double ) > - Signature< void (MyType::*)( char const * ) const > - @endcode - - This interface treates the "function parameter part" of its arguments as - a "type list", and several algorithms in the sl namespace are available - for fetching type information from a Signature type. This is an - "extended" typelist, however, because it also remembers the return type - and optionally the class containing a member function described by the - signature (neither of those are counted as part of the list, but are - accessible separately). - - Required interface for specializations: - - @code - typedef functionSignature FunctionType; // e.g. void () or void (T::*)() const. - typedef functionReturnType ReturnType; - typedef T Context; // void for non-member functions, non-vp-qualified T - // for all T members. const-qualified T for const members. - typedef firstArgType Head; // head type of type-list. - typedef Signature< RV (...)> Tail; // tail of type-list. (...)==arg types 2..N. - // When Arity==0, Head and Tail must both be tmp::NilType. For Arity==1 - // Tail is Signature but one could argue that it should be tmp::NilType. - - @endcode - - It is intended to be used like this: - - @code - typedef Signature< int (char const *, double) > Sig; - assert( 2 == sl::Arity::Value ); - assert( 2 == sl::Length::Value ) - assert( (tmp::SameType< char const *, sl::At<0,Sig>::Type >::Value) ); - assert( (tmp::SameType< double, sl::At<1,Sig>::Type >::Value) ); - assert( 1 == sl::Index< double, Sig >::Value) ); - assert( !sl::Contains< int, Sig >::Value) ); // Sig::ReturnType doesn't count here! - assert( sl::IsConstMethod< Signature< void (MyType::*)() const > >::Value ); - assert( sl::IsMethod< Signature< void (MyType::*)() const > >::Value ); - assert( !sl::IsConstMethod< Signature< void (MyType::*)() > >::Value ); - // Those can all be made into static assertions, by the way. - @endcode - - Note that the length of the typelist does not include the return value - type nor (for member methods) the containing class (the Context typedef). - - Functions taking one (v8::Arguments const &) argument and - returning any type are considered to be - "InvocationCallback-like" and are treated specially. They have - an Arity value of -1, which is used as a hint by binding code - that the function can accept any number of arguments when called - from JS code (there is no way to create Arguments objects - directly from C++, only indirectly via Call()ing or Apply()ing a - v8::Function). -*/ -template struct Signature DOXYGEN_FWD_DECL_KLUDGE; - -/** @def CVV8_TYPELIST - - CVV8_TYPELIST is a (slightly) convenience form of - Signature for creating typelists where we do not care about the - "return type" or "context" parts of the list. - - It is used like this: - - @code - typedef CVV8_TYPELIST(( int, double, char )) MyList; - @endcode - - NOTE the doubled parenthesis! - - Many members of the API which take a type-list require a - Signature-compatible typelist because they need the ReturnValue and/or - Context parts. CVV8_TYPELIST is intended for cases where niether the - ReturnValue nor Context are evaluated (both are void for CVV8_TYPELIST). - - The maximum number of types the typelist can hold is limited - to some build-time configuration option. -*/ -#define CVV8_TYPELIST(X) ::cvv8::Signature< void (*)X > - -/** \namespace cvv8::sl - - The sl namespace exclusively holds template metafunctions for working - with Signature-style typelists. -*/ -namespace sl { - - /** - Metafunction whose Value member evaluates to the length of the - given Signature. - */ - template < typename ListT > - struct Length : tmp::IntVal< - tmp::IsNil::Value ? 0 : (1 + Length::Value) - > {}; - - //! End-of-list specialization. - template <> - struct Length : tmp::IntVal<0> {}; - /** - Metafunction whose Type member evaluates to the type of the - I'th argument type in the given Signature. Fails to compile - if I is out of range. - */ - template < unsigned short I, typename ListT > - struct At : At - { - typedef char AssertIndex[ (I >= Length::Value) ? -1 : 1 ]; - }; - - //! Beginning-of-list specialization. - template < typename ListT > - struct At<0, ListT> - { - typedef typename ListT::Head Type; - }; - /** - End-of-list specialization. i don't think we need this, actually. - */ - template - struct At : tmp::Identity - {}; - - /** - Metafunction whose Type Value member evaluates to the 0-based - index of the first occurrance of the the type T in the - given Signature's argument list. Evaluates to -1 if T is not - contained in the argument list. Signature::ReturnType and - Signature::Context are not evaluated. - - Clients _must not_ pass a value for the 3rd template parameter. - */ - template < typename T, typename ListT, unsigned short Internal = 0 > - struct Index : tmp::IntVal< tmp::SameType::Value - ? Internal - : Index::Value> - { - }; - - //! End-of-list specialization. - template < typename T, unsigned short Internal > - struct Index : tmp::IntVal<-1> {}; - - /** - Convenience form of Index which evaluates to true - if Index returns a non-negative value, else it evaluates - to false. - */ - template < typename T, typename ListT> - struct Contains : tmp::BoolVal< Index::Value >= 0 > {}; - - - /** - A metatype which calculates the number of arguments in the given - typelist, but evaluates to -1 if SigT's only argument is - (v8::Arguments const &), as such function signatures are considered - to be n-arity. - */ - template - struct Arity - { - enum { - Value = ((1==Length::Value) - && (0==Index::Value)) - ? -1 - : Length::Value - }; - }; - - /** - This metafunction evaluates to true if SigT appears to be - "InvocationCallback-like" (returns any type and takes one - (v8::Arguments const &) parameter). - - We could implement this a number of different ways. The - current impl simply checks if the arity is -1. - */ - template - struct IsInCaLike : tmp::BoolVal< -1 == Arity::Value > {}; - - /** - A metafunction which has a true Value if the Signature type SigT - represents a non-member function. - */ - template - struct IsFunction : tmp::BoolVal< tmp::SameType::Value > {}; - - /** - A metafunction which has a true Value if the Signature type SigT - represents a member function (const or not). - */ - template - struct IsMethod : tmp::BoolVal< !tmp::SameType::Value > {}; - - /** - A metafunction which has a true Value if the Signature type SigT - represents a non-const member function. - */ - template - struct IsNonConstMethod : tmp::BoolVal< !tmp::IsConst< typename SigT::Context >::Value && IsMethod::Value > {}; - - /** - A metafunction which has a true Value if the Signature type SigT - represents a const member function. - */ - template - struct IsConstMethod : - tmp::BoolVal< tmp::IsConst< typename SigT::Context >::Value && IsMethod::Value > {}; - //tmp::BoolVal< SigT::IsConst && IsMethod::Value > {}; - -} - -namespace tmp { - /** - A metatemplate who's Type member resolves to IF if Cond is - true, or ELSE if Cond is false. Its Value member evaluates - to 1 or 0, accordingly. - */ - template - struct IfElse : sl::At< Cond ? 0 : 1, Signature > - { - }; -} - -#if 0 -//! Highly arguably specialization. -template struct Signature< Signature > : Signature {}; -#endif - -/** - Specialization to give "InvacationCallback-like" functions - an Arity value of -1. - - Reminder: we can get rid of this if we factory out the Arity definition - and use sl::Arity instead. -*/ -template -struct Signature -{ - typedef RV ReturnType; - typedef RV (*FunctionType)(v8::Arguments const &); - typedef void Context; - typedef v8::Arguments const & Head; - typedef Signature Tail; -}; - -template -struct Signature : Signature -{}; - -template -struct Signature : Signature -{ - typedef T Context; - typedef RV (Context::*FunctionType)(v8::Arguments const &); -}; - - -template -struct Signature : Signature -{ - typedef T const Context; - typedef RV (Context::*FunctionType)(v8::Arguments const &) const; -}; - - - -/** @class FunctionSignature - Base (unimplemented) signature for FunctionSignature - specializations. The type passed to it must be a function - signature. - - All implementations must define the interface described for - Signature and its Context typedef must be void for this type. - - Examples: - - @code - // void func_foo(): - typedef FunctionSignature< void () > NoArgsReturnsVoid; - - // int func_foo(double): - typedef FunctionSignature< int (double) > OneArgReturnsInt; - - // double func_foo(int,int): - typedef FunctionSignature< double (int,int) > TwoArgsReturnsDouble; - @endcode - -*/ -template -struct FunctionSignature : Signature< FunctionSig > {}; - -/** @class MethodSignature - Base (unimplemented) signature for MethodSignature - specializations. The Sig type passed to it must match a member method - signature of a function from the class T. - e.g. (void (T::*)(int)) or its equivalent (void (int)). - - All implementations must have the interface called for by Signature - and the Context typedef must be non-cvp-qualified T. - - Examples: - - @code - // void MyType::func(): - typedef MethodSignature< MyType, void () > NoArgsReturnsVoid; - - // int MyType::func(double): - typedef MethodSignature< MyType, int (double) > OneArgReturnsInt; - - // double MyType::func(int,int): - typedef MethodSignature< MyType, double (int,int) > TwoArgsReturnsDouble; - @endcode - - As of r2019 (20110723), MethodSignature and - ConstMethodSignature are equivalent. - - Reminders to self: - - i would really like this class to simply subclass Signature and we - would add in a couple typedefs we need. This would cut the specializations - we generate. However, i don't know how to make this work. The problems - include: - - - i can't "refactor" Signature::FunctionType to the proper type - at this level. -*/ -template -struct MethodSignature DOXYGEN_FWD_DECL_KLUDGE; - -/** @class ConstMethodSignature - Base (unimplemented) signature for ConstMethodSignature - specializations. The Sig type passed to it must be a member - method signature of a const function from the class T. - e.g. (void (T::*)(int) const) - - All implementations must have the interface called for by Signature - and the Context typedef must be non-cvp-qualified T. The IsConst - member (enum or static/const boolean) must be a true value. - - Examples: - - @code - // void MyType::func() const: - typedef ConstMethodSignature< MyType, void () > NoArgsReturnsVoid; - - // int MyType::func(double) const: - typedef ConstMethodSignature< MyType, int (double) > OneArgReturnsInt; - - // double MyType::func(int,int) const: - typedef ConstMethodSignature< MyType, double (int,int) > TwoArgsReturnsDouble; - @endcode - - As of r2019 (20110723), MethodSignature and - ConstMethodSignature are equivalent. -*/ -template -struct ConstMethodSignature DOXYGEN_FWD_DECL_KLUDGE; -//template -//struct ConstMethodSignature : ConstMethodSignature {}; - -template -struct MethodSignature< T, RV () > : Signature< RV () > -{ - typedef T Context; - typedef RV (Context::*FunctionType)(); -}; - - -template -struct MethodSignature< T, RV (T::*)() > : MethodSignature -{ -}; - -template -struct MethodSignature< T const, RV () > : ConstMethodSignature< T, RV () > -{}; - -template -struct MethodSignature< T const, RV (T::*)() > : MethodSignature -{ -}; -#if 1 //msvc? -template -struct MethodSignature< T const, RV (T::*)() const > : MethodSignature -{ -}; -#endif - -template -struct ConstMethodSignature< T, RV () > : Signature< RV (T::*)() const > -{ - typedef T const Context; - typedef RV (Context::*FunctionType)() const; -}; -template -struct ConstMethodSignature< T, RV (T::*)() const > : ConstMethodSignature -{ -}; - - -/** - A "type-rich" function pointer. - - Sig must be a function signature type usable in the construct - FunctionSignature. FuncPtr must be a function of that type. -*/ -template ::FunctionType FuncPtr> -struct FunctionPtr : FunctionSignature -{ - /** - This type's full "signature" type. - */ - typedef FunctionSignature SignatureType; - /** - The data type of FuncPtr. - */ - typedef typename SignatureType::FunctionType FunctionType; - - /** The function specifies in the template arguments. */ - static const FunctionType Function; -}; -template ::FunctionType FuncPtr> -typename FunctionPtr::FunctionType const FunctionPtr::Function = FuncPtr; - -/** - Used like FunctionPtr, but in conjunction with non-const - member functions ("methods") of the T class. See FunctionPtr - for the requirements of the Sig type. -*/ -template ::FunctionType FuncPtr> -struct MethodPtr : MethodSignature -{ - typedef MethodSignature SignatureType; - typedef typename SignatureType::FunctionType FunctionType; - static const FunctionType Function; -}; -template ::FunctionType FuncPtr> -typename MethodPtr::FunctionType const MethodPtr::Function = FuncPtr; -/** - Used like MethodPtr, but in conjunction with const methods of the T - class. -*/ -template ::FunctionType FuncPtr> -struct ConstMethodPtr : ConstMethodSignature -{ - typedef ConstMethodSignature SignatureType; - typedef typename SignatureType::FunctionType FunctionType; - static const FunctionType Function; -}; -template ::FunctionType FuncPtr> -typename ConstMethodPtr::FunctionType const ConstMethodPtr::Function = FuncPtr; - -#if 0 //!msvc -//! Specialization to treat (const T) as ConstMethodPtr. -template ::FunctionType FuncPtr> -struct MethodPtr : ConstMethodPtr -{ - typedef MethodSignature SignatureType; - typedef typename SignatureType::FunctionType FunctionType; - static const FunctionType Function; -}; -#endif - -#include "signature_generated.hpp" -} // namespaces - -#endif /* CODE_GOOGLE_COM_V8_CONVERT_SIGNATURE_CORE_HPP_INCLUDED */ diff --git a/vendor/libv8-convert/cvv8/detail/signature_generated.hpp b/vendor/libv8-convert/cvv8/detail/signature_generated.hpp deleted file mode 100644 index 30102c1f2..000000000 --- a/vendor/libv8-convert/cvv8/detail/signature_generated.hpp +++ /dev/null @@ -1,911 +0,0 @@ -/* AUTO-GENERATED CODE! EDIT AT YOUR OWN RISK! */ -#if !defined(DOXYGEN) - -template -struct Signature< RV () > -{ - typedef RV ReturnType; - enum { IsConst = 0 }; - typedef void Context; - typedef RV (*FunctionType)(); - typedef tmp::NilType Head; - typedef Head Tail; -}; -template -struct Signature< RV (*)() > : Signature -{}; - -template -struct Signature< RV (T::*)() > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(); -}; -template -struct Signature< RV (T::*)() const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)() const; - enum { IsConst = 1 }; -}; -//! Specialization for 1 arg(s). -template -struct Signature< RV (A1) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1); - typedef A1 Head; - typedef Signature< RV () > Tail; -}; - -//! Specialization for 1 arg(s). -template -struct Signature< RV (*)(A1) > : Signature -{}; - -//! Specialization for T non-const methods taking 1 arg(s). -template -struct Signature< RV (T::*)(A1) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1); -}; - -//! Specialization for T const methods taking 1 arg(s). -template -struct Signature< RV (T::*)(A1) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1) const; -}; - -//! Specialization for 2 arg(s). -template -struct Signature< RV (A1, A2) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1, A2); - typedef A1 Head; - typedef Signature Tail; -}; - -//! Specialization for 2 arg(s). -template -struct Signature< RV (*)(A1, A2) > : Signature -{}; - -//! Specialization for T non-const methods taking 2 arg(s). -template -struct Signature< RV (T::*)(A1, A2) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1, A2); -}; - -//! Specialization for T const methods taking 2 arg(s). -template -struct Signature< RV (T::*)(A1, A2) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1, A2) const; -}; - -//! Specialization for 3 arg(s). -template -struct Signature< RV (A1, A2, A3) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1, A2, A3); - typedef A1 Head; - typedef Signature Tail; -}; - -//! Specialization for 3 arg(s). -template -struct Signature< RV (*)(A1, A2, A3) > : Signature -{}; - -//! Specialization for T non-const methods taking 3 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1, A2, A3); -}; - -//! Specialization for T const methods taking 3 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1, A2, A3) const; -}; - -//! Specialization for 4 arg(s). -template -struct Signature< RV (A1, A2, A3, A4) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1, A2, A3, A4); - typedef A1 Head; - typedef Signature Tail; -}; - -//! Specialization for 4 arg(s). -template -struct Signature< RV (*)(A1, A2, A3, A4) > : Signature -{}; - -//! Specialization for T non-const methods taking 4 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4); -}; - -//! Specialization for T const methods taking 4 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4) const; -}; - -//! Specialization for 5 arg(s). -template -struct Signature< RV (A1, A2, A3, A4, A5) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1, A2, A3, A4, A5); - typedef A1 Head; - typedef Signature Tail; -}; - -//! Specialization for 5 arg(s). -template -struct Signature< RV (*)(A1, A2, A3, A4, A5) > : Signature -{}; - -//! Specialization for T non-const methods taking 5 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5); -}; - -//! Specialization for T const methods taking 5 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5) const; -}; - -//! Specialization for 6 arg(s). -template -struct Signature< RV (A1, A2, A3, A4, A5, A6) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1, A2, A3, A4, A5, A6); - typedef A1 Head; - typedef Signature Tail; -}; - -//! Specialization for 6 arg(s). -template -struct Signature< RV (*)(A1, A2, A3, A4, A5, A6) > : Signature -{}; - -//! Specialization for T non-const methods taking 6 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6); -}; - -//! Specialization for T const methods taking 6 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6) const; -}; - -//! Specialization for 7 arg(s). -template -struct Signature< RV (A1, A2, A3, A4, A5, A6, A7) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1, A2, A3, A4, A5, A6, A7); - typedef A1 Head; - typedef Signature Tail; -}; - -//! Specialization for 7 arg(s). -template -struct Signature< RV (*)(A1, A2, A3, A4, A5, A6, A7) > : Signature -{}; - -//! Specialization for T non-const methods taking 7 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7); -}; - -//! Specialization for T const methods taking 7 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7) const; -}; - -//! Specialization for 8 arg(s). -template -struct Signature< RV (A1, A2, A3, A4, A5, A6, A7, A8) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8); - typedef A1 Head; - typedef Signature Tail; -}; - -//! Specialization for 8 arg(s). -template -struct Signature< RV (*)(A1, A2, A3, A4, A5, A6, A7, A8) > : Signature -{}; - -//! Specialization for T non-const methods taking 8 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8); -}; - -//! Specialization for T const methods taking 8 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8) const; -}; - -//! Specialization for 9 arg(s). -template -struct Signature< RV (A1, A2, A3, A4, A5, A6, A7, A8, A9) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9); - typedef A1 Head; - typedef Signature Tail; -}; - -//! Specialization for 9 arg(s). -template -struct Signature< RV (*)(A1, A2, A3, A4, A5, A6, A7, A8, A9) > : Signature -{}; - -//! Specialization for T non-const methods taking 9 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9); -}; - -//! Specialization for T const methods taking 9 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9) const; -}; - -//! Specialization for 10 arg(s). -template -struct Signature< RV (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); - typedef A1 Head; - typedef Signature Tail; -}; - -//! Specialization for 10 arg(s). -template -struct Signature< RV (*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) > : Signature -{}; - -//! Specialization for T non-const methods taking 10 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); -}; - -//! Specialization for T const methods taking 10 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) const; -}; - -//! Specialization for 11 arg(s). -template -struct Signature< RV (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); - typedef A1 Head; - typedef Signature Tail; -}; - -//! Specialization for 11 arg(s). -template -struct Signature< RV (*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) > : Signature -{}; - -//! Specialization for T non-const methods taking 11 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); -}; - -//! Specialization for T const methods taking 11 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) const; -}; - -//! Specialization for 12 arg(s). -template -struct Signature< RV (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); - typedef A1 Head; - typedef Signature Tail; -}; - -//! Specialization for 12 arg(s). -template -struct Signature< RV (*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) > : Signature -{}; - -//! Specialization for T non-const methods taking 12 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); -}; - -//! Specialization for T const methods taking 12 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) const; -}; - -//! Specialization for 13 arg(s). -template -struct Signature< RV (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); - typedef A1 Head; - typedef Signature Tail; -}; - -//! Specialization for 13 arg(s). -template -struct Signature< RV (*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) > : Signature -{}; - -//! Specialization for T non-const methods taking 13 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); -}; - -//! Specialization for T const methods taking 13 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) const; -}; - -//! Specialization for 14 arg(s). -template -struct Signature< RV (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); - typedef A1 Head; - typedef Signature Tail; -}; - -//! Specialization for 14 arg(s). -template -struct Signature< RV (*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) > : Signature -{}; - -//! Specialization for T non-const methods taking 14 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); -}; - -//! Specialization for T const methods taking 14 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) const; -}; - -//! Specialization for 15 arg(s). -template -struct Signature< RV (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) > -{ - typedef RV ReturnType; - typedef void Context; - typedef RV (*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); - typedef A1 Head; - typedef Signature Tail; -}; - -//! Specialization for 15 arg(s). -template -struct Signature< RV (*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) > : Signature -{}; - -//! Specialization for T non-const methods taking 15 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) > : Signature -{ - typedef T Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); -}; - -//! Specialization for T const methods taking 15 arg(s). -template -struct Signature< RV (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) const > : Signature -{ - typedef T const Context; - typedef RV (T::*FunctionType)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) const; -}; - -template -struct MethodSignature< T, RV ( A0) > : Signature< RV (T::*)( A0) > -{ -}; -template -struct MethodSignature< T, RV (*)( A0) > : MethodSignature< T, RV ( A0) > -{ -}; - -template -struct MethodSignature< T, RV (T::*)( A0) > : - MethodSignature< T, RV ( A0) > -{}; - -template -struct MethodSignature< T const, RV ( A0) > : - ConstMethodSignature< T, RV ( A0) > -{}; - -template -struct MethodSignature< T const, RV (T::*)( A0) > : - MethodSignature< T const, RV ( A0) > -{}; - -#if 1 // msvc? Apparently this works. -template -struct MethodSignature< T const, RV (T::*)( A0) const > : - MethodSignature< T const, RV ( A0) > -{}; -#endif - - -template -struct ConstMethodSignature< T, RV ( A0) > : Signature< RV (T::*)( A0) const > -{ -}; -template -struct ConstMethodSignature< T, RV (T::*)( A0) const > : - ConstMethodSignature< T, RV ( A0) > -{}; -template -struct MethodSignature< T, RV ( A0, A1) > : Signature< RV (T::*)( A0, A1) > -{ -}; -template -struct MethodSignature< T, RV (*)( A0, A1) > : MethodSignature< T, RV ( A0, A1) > -{ -}; - -template -struct MethodSignature< T, RV (T::*)( A0, A1) > : - MethodSignature< T, RV ( A0, A1) > -{}; - -template -struct MethodSignature< T const, RV ( A0, A1) > : - ConstMethodSignature< T, RV ( A0, A1) > -{}; - -template -struct MethodSignature< T const, RV (T::*)( A0, A1) > : - MethodSignature< T const, RV ( A0, A1) > -{}; - -#if 1 // msvc? Apparently this works. -template -struct MethodSignature< T const, RV (T::*)( A0, A1) const > : - MethodSignature< T const, RV ( A0, A1) > -{}; -#endif - - -template -struct ConstMethodSignature< T, RV ( A0, A1) > : Signature< RV (T::*)( A0, A1) const > -{ -}; -template -struct ConstMethodSignature< T, RV (T::*)( A0, A1) const > : - ConstMethodSignature< T, RV ( A0, A1) > -{}; -template -struct MethodSignature< T, RV ( A0, A1, A2) > : Signature< RV (T::*)( A0, A1, A2) > -{ -}; -template -struct MethodSignature< T, RV (*)( A0, A1, A2) > : MethodSignature< T, RV ( A0, A1, A2) > -{ -}; - -template -struct MethodSignature< T, RV (T::*)( A0, A1, A2) > : - MethodSignature< T, RV ( A0, A1, A2) > -{}; - -template -struct MethodSignature< T const, RV ( A0, A1, A2) > : - ConstMethodSignature< T, RV ( A0, A1, A2) > -{}; - -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2) > : - MethodSignature< T const, RV ( A0, A1, A2) > -{}; - -#if 1 // msvc? Apparently this works. -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2) const > : - MethodSignature< T const, RV ( A0, A1, A2) > -{}; -#endif - - -template -struct ConstMethodSignature< T, RV ( A0, A1, A2) > : Signature< RV (T::*)( A0, A1, A2) const > -{ -}; -template -struct ConstMethodSignature< T, RV (T::*)( A0, A1, A2) const > : - ConstMethodSignature< T, RV ( A0, A1, A2) > -{}; -template -struct MethodSignature< T, RV ( A0, A1, A2, A3) > : Signature< RV (T::*)( A0, A1, A2, A3) > -{ -}; -template -struct MethodSignature< T, RV (*)( A0, A1, A2, A3) > : MethodSignature< T, RV ( A0, A1, A2, A3) > -{ -}; - -template -struct MethodSignature< T, RV (T::*)( A0, A1, A2, A3) > : - MethodSignature< T, RV ( A0, A1, A2, A3) > -{}; - -template -struct MethodSignature< T const, RV ( A0, A1, A2, A3) > : - ConstMethodSignature< T, RV ( A0, A1, A2, A3) > -{}; - -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2, A3) > : - MethodSignature< T const, RV ( A0, A1, A2, A3) > -{}; - -#if 1 // msvc? Apparently this works. -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2, A3) const > : - MethodSignature< T const, RV ( A0, A1, A2, A3) > -{}; -#endif - - -template -struct ConstMethodSignature< T, RV ( A0, A1, A2, A3) > : Signature< RV (T::*)( A0, A1, A2, A3) const > -{ -}; -template -struct ConstMethodSignature< T, RV (T::*)( A0, A1, A2, A3) const > : - ConstMethodSignature< T, RV ( A0, A1, A2, A3) > -{}; -template -struct MethodSignature< T, RV ( A0, A1, A2, A3, A4) > : Signature< RV (T::*)( A0, A1, A2, A3, A4) > -{ -}; -template -struct MethodSignature< T, RV (*)( A0, A1, A2, A3, A4) > : MethodSignature< T, RV ( A0, A1, A2, A3, A4) > -{ -}; - -template -struct MethodSignature< T, RV (T::*)( A0, A1, A2, A3, A4) > : - MethodSignature< T, RV ( A0, A1, A2, A3, A4) > -{}; - -template -struct MethodSignature< T const, RV ( A0, A1, A2, A3, A4) > : - ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4) > -{}; - -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2, A3, A4) > : - MethodSignature< T const, RV ( A0, A1, A2, A3, A4) > -{}; - -#if 1 // msvc? Apparently this works. -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2, A3, A4) const > : - MethodSignature< T const, RV ( A0, A1, A2, A3, A4) > -{}; -#endif - - -template -struct ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4) > : Signature< RV (T::*)( A0, A1, A2, A3, A4) const > -{ -}; -template -struct ConstMethodSignature< T, RV (T::*)( A0, A1, A2, A3, A4) const > : - ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4) > -{}; -template -struct MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5) > : Signature< RV (T::*)( A0, A1, A2, A3, A4, A5) > -{ -}; -template -struct MethodSignature< T, RV (*)( A0, A1, A2, A3, A4, A5) > : MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5) > -{ -}; - -template -struct MethodSignature< T, RV (T::*)( A0, A1, A2, A3, A4, A5) > : - MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5) > -{}; - -template -struct MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5) > : - ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5) > -{}; - -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2, A3, A4, A5) > : - MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5) > -{}; - -#if 1 // msvc? Apparently this works. -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2, A3, A4, A5) const > : - MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5) > -{}; -#endif - - -template -struct ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5) > : Signature< RV (T::*)( A0, A1, A2, A3, A4, A5) const > -{ -}; -template -struct ConstMethodSignature< T, RV (T::*)( A0, A1, A2, A3, A4, A5) const > : - ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5) > -{}; -template -struct MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6) > : Signature< RV (T::*)( A0, A1, A2, A3, A4, A5, A6) > -{ -}; -template -struct MethodSignature< T, RV (*)( A0, A1, A2, A3, A4, A5, A6) > : MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6) > -{ -}; - -template -struct MethodSignature< T, RV (T::*)( A0, A1, A2, A3, A4, A5, A6) > : - MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6) > -{}; - -template -struct MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5, A6) > : - ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6) > -{}; - -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2, A3, A4, A5, A6) > : - MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5, A6) > -{}; - -#if 1 // msvc? Apparently this works. -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2, A3, A4, A5, A6) const > : - MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5, A6) > -{}; -#endif - - -template -struct ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6) > : Signature< RV (T::*)( A0, A1, A2, A3, A4, A5, A6) const > -{ -}; -template -struct ConstMethodSignature< T, RV (T::*)( A0, A1, A2, A3, A4, A5, A6) const > : - ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6) > -{}; -template -struct MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7) > : Signature< RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7) > -{ -}; -template -struct MethodSignature< T, RV (*)( A0, A1, A2, A3, A4, A5, A6, A7) > : MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7) > -{ -}; - -template -struct MethodSignature< T, RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7) > : - MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7) > -{}; - -template -struct MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5, A6, A7) > : - ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7) > -{}; - -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7) > : - MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5, A6, A7) > -{}; - -#if 1 // msvc? Apparently this works. -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7) const > : - MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5, A6, A7) > -{}; -#endif - - -template -struct ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7) > : Signature< RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7) const > -{ -}; -template -struct ConstMethodSignature< T, RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7) const > : - ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7) > -{}; -template -struct MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8) > : Signature< RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7, A8) > -{ -}; -template -struct MethodSignature< T, RV (*)( A0, A1, A2, A3, A4, A5, A6, A7, A8) > : MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8) > -{ -}; - -template -struct MethodSignature< T, RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7, A8) > : - MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8) > -{}; - -template -struct MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8) > : - ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8) > -{}; - -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7, A8) > : - MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8) > -{}; - -#if 1 // msvc? Apparently this works. -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7, A8) const > : - MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8) > -{}; -#endif - - -template -struct ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8) > : Signature< RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7, A8) const > -{ -}; -template -struct ConstMethodSignature< T, RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7, A8) const > : - ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8) > -{}; -template -struct MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) > : Signature< RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) > -{ -}; -template -struct MethodSignature< T, RV (*)( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) > : MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) > -{ -}; - -template -struct MethodSignature< T, RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) > : - MethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) > -{}; - -template -struct MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) > : - ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) > -{}; - -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) > : - MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) > -{}; - -#if 1 // msvc? Apparently this works. -template -struct MethodSignature< T const, RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) const > : - MethodSignature< T const, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) > -{}; -#endif - - -template -struct ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) > : Signature< RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) const > -{ -}; -template -struct ConstMethodSignature< T, RV (T::*)( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) const > : - ConstMethodSignature< T, RV ( A0, A1, A2, A3, A4, A5, A6, A7, A8, A9) > -{}; -#endif // if !defined(DOXYGEN) diff --git a/vendor/libv8-convert/cvv8/detail/tmp.hpp b/vendor/libv8-convert/cvv8/detail/tmp.hpp deleted file mode 100644 index aff069f6c..000000000 --- a/vendor/libv8-convert/cvv8/detail/tmp.hpp +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef CODE_GOOGLE_COM_P_V8_CONVERT_TMP_HPP_INCLUDED -#define CODE_GOOGLE_COM_P_V8_CONVERT_TMP_HPP_INCLUDED - -namespace cvv8 { -/** - The tmp namespace contains code related to template - metaprogramming, a-la Alexandrescu's Loki library or Boost MPL. - - All of it is independent of the core library. - - This is not a complete/full-featured TMP library - it only - contains the functions needed by our library-level code. -*/ -namespace tmp { - - struct NilType {}; - typedef NilType nil; - - - /** - An utmost most-basic compile-time assertion template. - If Condition is false, an incomplete specialization of - this type is invoked, causing a compile-time error. - */ - template - struct Assertion - { - enum { Value = 1 }; - }; - /** Unimplemented - causes a compile-time error if used. */ - template <> - struct Assertion; - - - /** A convenience base type for metafunctions holding a constant value. */ - template - struct ConstVal - { - static const ValType Value = Val; - }; - /** A metafunction holding an integer constant. */ - template - struct IntVal : ConstVal {}; - /** A metafunction holding an unsigned short constant. */ - template - struct UShortVal : ConstVal {}; - /** A metafunction holding a bool constant. */ - template - struct BoolVal : ConstVal {}; - - /** A metatype whos Value member is true if X and Y are the same type. */ - template - struct SameType : BoolVal {}; - /** Specialization for X==Y. */ - template - struct SameType : BoolVal {}; - - template - struct Identity - { - typedef T Type; - }; - - template - struct PlainType - { - typedef T Type; - }; - template - struct PlainType : PlainType {}; - template - struct PlainType : PlainType {}; - template - struct PlainType : PlainType {}; - -#if 0 - /** Metatemplate whose Type evaluates to (T*). */ - template - struct AddPointer - { - typedef T * Type; - }; - /** Specialization whose Type evaluates to (T *). */ - template - struct AddPointer - { - typedef T * Type; - }; - /** Specialization whose Type evaluates to (T const *). */ - template - struct AddPointer - { - typedef T const * Type; - }; - - //! Unimplemented. How to handle this? - template - struct AddPointer; - //! Unimplemented. How to handle this? - template - struct AddPointer; -#endif - - template - struct IsConst : BoolVal {}; - template - struct IsConst : BoolVal {}; - template - struct IsConst : IsConst {}; - template - struct IsConst : IsConst {}; - - - template - struct IsNil : SameType {}; - - - -}} // namespaces -#endif // CODE_GOOGLE_COM_P_V8_CONVERT_TMP_HPP_INCLUDED diff --git a/vendor/libv8-convert/cvv8/generator/Signature.hpp b/vendor/libv8-convert/cvv8/generator/Signature.hpp deleted file mode 100644 index 969a5e54b..000000000 --- a/vendor/libv8-convert/cvv8/generator/Signature.hpp +++ /dev/null @@ -1,72 +0,0 @@ -#if !defined(BOOST_PP_IS_ITERATING) -# include -# include -# include -# include -# include -# if !defined(CVV8_PP_ITER_MAX) -# error "Define CVV8_PP_ITER_MAX before including this file." -# endif -# if !defined(CVV8_SIGNATURE_GENERATED_HPP_INCLUDED) -# define BOOST_PP_ITERATION_LIMITS (0, CVV8_PP_ITER_MAX) -# define BOOST_PP_FILENAME_1 "Signature.hpp" -# include BOOST_PP_ITERATE() -# endif /* include guard */ -#else -#define n BOOST_PP_ITERATION() - -template -struct Signature< RV (BOOST_PP_ENUM_PARAMS(n, A)) > -{ - typedef RV ReturnType; - static const bool IsConst = false; - typedef void Context; - typedef RV (*FunctionType)(BOOST_PP_ENUM_PARAMS(n, A)); -#if n > 0 - typedef A0 Head; - typedef Signature< RV (BOOST_PP_ENUM_SHIFTED_PARAMS(n, A)) > Tail; -#else - typedef tmp::NilType Head; - typedef Head Tail; -#endif -}; - -template -struct Signature< RV (*)(BOOST_PP_ENUM_PARAMS(n, A)) > - : Signature< RV (BOOST_PP_ENUM_PARAMS(n, A)) > -{}; - -//! Non-const method. -template -struct Signature< RV (T::*)(BOOST_PP_ENUM_PARAMS(n, A)) > - : Signature< RV (BOOST_PP_ENUM_PARAMS(n, A))> -{ - typedef T Context; - typedef RV (Context::*FunctionType)(BOOST_PP_ENUM_PARAMS(n, A)); -#if n > 0 - typedef A0 Head; - typedef Signature< RV (T::*)(BOOST_PP_ENUM_SHIFTED_PARAMS(n, A)) > Tail; -#else - typedef tmp::NilType Head; - typedef Head Tail; -#endif -}; - -//! Const method. -template -struct Signature< RV (T::*)(BOOST_PP_ENUM_PARAMS(n, A)) const > - : Signature< RV (BOOST_PP_ENUM_PARAMS(n, A))> -{ - typedef T const Context; - typedef RV (Context::*FunctionType)(BOOST_PP_ENUM_PARAMS(n, A)) const; - static const bool IsConst = true; -#if n > 0 - typedef A0 Head; - typedef Signature< RV (T::*)(BOOST_PP_ENUM_SHIFTED_PARAMS(n, A)) const > Tail; -#else - typedef tmp::NilType Head; - typedef Head Tail; -#endif -}; - -#endif /* BOOST_PP_IS_ITERATING */ diff --git a/vendor/libv8-convert/cvv8/invocable.hpp b/vendor/libv8-convert/cvv8/invocable.hpp deleted file mode 100644 index dac513380..000000000 --- a/vendor/libv8-convert/cvv8/invocable.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#if !defined(CODE_GOOGLE_COM_P_V8_CONVERT_INVOKE_HPP_INCLUDED) -#define CODE_GOOGLE_COM_P_V8_CONVERT_INVOKE_HPP_INCLUDED 1 - -#include "convert.hpp" -#include "detail/invocable_core.hpp" -/** LICENSE - - This software's source code, including accompanying documentation and - demonstration applications, are licensed under the following - conditions... - - The author (Stephan G. Beal [http://wanderinghorse.net/home/stephan/]) - explicitly disclaims copyright in all jurisdictions which recognize - such a disclaimer. In such jurisdictions, this software is released - into the Public Domain. - - In jurisdictions which do not recognize Public Domain property - (e.g. Germany as of 2011), this software is Copyright (c) 2011 - by Stephan G. Beal, and is released under the terms of the MIT License - (see below). - - In jurisdictions which recognize Public Domain property, the user of - this software may choose to accept it either as 1) Public Domain, 2) - under the conditions of the MIT License (see below), or 3) under the - terms of dual Public Domain/MIT License conditions described here, as - they choose. - - The MIT License is about as close to Public Domain as a license can - get, and is described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - - The full text of the MIT License follows: - - -- - Copyright (c) 2011 Stephan G. Beal (http://wanderinghorse.net/home/stephan/) - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - --END OF MIT LICENSE-- - - For purposes of the above license, the term "Software" includes - documentation and demonstration source code which accompanies - this software. ("Accompanies" = is contained in the Software's - primary public source code repository.) - -*/ -#endif /* CODE_GOOGLE_COM_P_V8_CONVERT_INVOKE_HPP_INCLUDED */ diff --git a/vendor/libv8-convert/cvv8/properties.hpp b/vendor/libv8-convert/cvv8/properties.hpp deleted file mode 100644 index 1b4b936ad..000000000 --- a/vendor/libv8-convert/cvv8/properties.hpp +++ /dev/null @@ -1,730 +0,0 @@ -#if !defined(CODE_GOOGLE_COM_P_V8_CONVERT_PROPERTIES_HPP_INCLUDED) -#define CODE_GOOGLE_COM_P_V8_CONVERT_PROPERTIES_HPP_INCLUDED 1 - -#include "invocable.hpp" - -namespace cvv8 { - - /** - Marker class, primarily for documentation purposes. - - This class models the v8::AccessorGetter interface, and - XyzToGetter classes inherit this type as a sign that they - implement this interface. - - This class has no implemention - it only exists for - documentation purposes. - */ - struct AccessorGetterType - { - /** - The v8::AccessorGetter() interface. - */ - static v8::Handle Get(v8::Local property, const v8::AccessorInfo &info); - //{ return Toss(StringBuffer()<<"Property '"< property, v8::Local value, const v8::AccessorInfo& info); - }; - - /** @typedef AccessorGetterType Getter - - Convenience typedef, primarily to simplify usage of - FunctionTo and friends. - */ - typedef AccessorGetterType Getter; - - /** @typedef AccessorSetterType Setter - - Convenience typedef, primarily to simplify usage of - FunctionTo and friends. - */ - typedef AccessorSetterType Setter; - - /** - A tag type for use with VarTo, MemberTo, MethodTo, and FunctionTo. - */ - struct Accessors : AccessorGetterType, AccessorSetterType {}; - - /** - This template create an v8::AccessorGetter from a static/shared - variable. - - SharedVar must be pointer to a static variable and must not - be NULL. - - CastToJS(*SharedVar) must be legal. - */ - template - struct VarToGetter : AccessorGetterType - { - /** Implements the v8::AccessorGetter() interface. */ - inline static v8::Handle Get(v8::Local property, const v8::AccessorInfo &info) - { - return CastToJS( *SharedVar ); - } - }; - - /** - The setter counterpart of StaticVarToGetter(). - - SharedVar must be pointer to a static variable and must not - be NULL. - - (*SharedVar = CastFromJS()) must be legal. - - Reminder: this is not included in the StaticVarToGetter - template so that we can avoid either the Get or Set - conversion for cases where it is not legal (or not desired). - If they were both in one class, both Get and Set would _have_ - to be legal. - */ - template - struct VarToSetter : AccessorSetterType - { - /** Implements the v8::AccessorSetter() interface. */ - inline static void Set(v8::Local property, v8::Local value, const v8::AccessorInfo& info) - { - *SharedVar = CastFromJS( value ); - } - }; - - /** - A proxy for both VarToGetter and VarToSetter, providing both - Get() and Set() functions. - */ - template - struct VarToAccessors : VarToGetter, - VarToSetter - {}; - - /** - This template creates a v8::AcessorGetter which binds directly to - a non-const native class member variable. - - Requirements: - - - T must be convertible to (T*) via CastFromJS(). - - MemVar must be an accessible member of T. - - PropertyType must be convertible via CastToJS(). - - If the underlying native 'this' object cannot be found (that - is, if CastFromJS() fails) then this routine will - trigger a JS exception. - */ - template - struct MemberToGetter : AccessorGetterType - { - /** Implements the v8::AccessorGetter() interface. */ - inline static v8::Handle Get(v8::Local property, const v8::AccessorInfo &info) - { - typedef typename TypeInfo::Type Type; - typedef typename JSToNative::ResultType NativeHandle; - NativeHandle self = CastFromJS( info.This() ); - return ( ! self ) - ? Toss( StringBuffer() << "Native member property getter '" - << property << "' could not access native 'this' object!" ) - : CastToJS( (self->*MemVar) ); - } - }; - - /** - This is the Setter counterpart of MemberToGetter. - - Requirements: - - - T must be convertible to (T*) via CastFromJS(). - - PropertyType must be convertible via CastToJS(). - - MemVar must be an accessible member of T. - - If the underlying native This object cannot be found then this - routine will trigger a JS exception. - */ - template - struct MemberToSetter : AccessorSetterType - { - /** Implements the v8::AccessorSetter() interface. */ - inline static void Set(v8::Local property, v8::Local value, const v8::AccessorInfo& info) - { - typedef typename TypeInfo::Type Type; - typedef typename JSToNative::ResultType NativeHandle; - NativeHandle self = CastFromJS( info.This() ); - if( self ) self->*MemVar = CastFromJS( value ); - else Toss( StringBuffer() << "Native member property setter '" - << property << "' could not access native 'this'his object!" ); - } - }; - - /** - A proxy for both MemberToGetter and MemberToSetter, providing both - Get() and Set() functions. - - This should be called MembersToAccessors (plural Members). - */ - template - struct MemberToAccessors : MemberToGetter, - MemberToSetter - {}; - - /** - An AccessorSetter() implementation which always triggers a JS exception. - Can be used to enforce "pedantically read-only" variables. Note that - JS does not allow us to assign an AccessorSetter _without_ assigning - an AccessorGetter. Also note that there is no AccessorGetterThrow, - because a write-only var doesn't make all that much sense (use - methods for those use cases). - */ - struct ThrowingSetter : AccessorSetterType - { - inline static void Set(v8::Local property, v8::Local, const v8::AccessorInfo &) - { - Toss(StringBuffer() << - "Native member property setter '" - << property - << "' is configured to throw an exception when modifying " - << "this read-only member!"); - } - }; - - /** - Implements the v8::AccessorGetter interface to bind a JS - member property to a native getter function. This function - can be used as the getter parameter to - v8::ObjectTemplate::SetAccessor(). - - Sig must be a function-signature-style type and Getter must - capable of being called with no arguments and returning a - value which can be CastToJS() to a JS value. - - If Getter() throws a native exception it is converted to a JS - exception. - */ - template ::FunctionType Getter> - struct FunctionToGetter : AccessorGetterType - { - inline static v8::Handle Get( v8::Local< v8::String > property, const v8::AccessorInfo & info ) - { - return CastToJS( (*Getter)() ); - } - }; - - /** - Implements the v8::AccessorSetter interface to bind a JS - member property to a native getter function. This function - can be used as the getter parameter to - v8::ObjectTemplate::SetAccessor(). - - SigSet must be function-signature-style pattern - for the setter function. The native - function must follow conventional mutator signature: - - ReturnType ( PropertyType ) - - PropertyType may differ from the return type. PropertyType - may not be void but the ReturnType may be. Any return value - from the setter is ignored by the JS engine. - - Note that the v8 API appears to not allow us to just set - a setter, but not a getter. We have to set a getter without - a setter, a getter with a setter, or neither. At least that's - been my experience. - - If Setter() throws a native exception it is converted to a JS - exception. - */ - template ::FunctionType Func> - struct FunctionToSetter : AccessorSetterType - { - inline static void Set( v8::Local< v8::String > property, v8::Local< v8::Value > value, const v8::AccessorInfo &info) - { - typedef FunctionSignature FT; - (*Func)( CastFromJS::Type>( value ) ); - } - }; - - - /** - Implements the v8::AccessorGetter interface to bind a JS - member property to a native getter function. This function - can be used as the getter parameter to - v8::ObjectTemplate::SetAccessor(). - - Sig must be a function-pointer-style argument with a - non-void return type convertible to v8 via CastToJS(), and - Getter must be function capable of being called with 0 - arguments (either because it has none or they have - defaults). - */ - template ::FunctionType Getter> - struct MethodToGetter : AccessorGetterType - { - inline static v8::Handle Get( v8::Local< v8::String > property, const v8::AccessorInfo & info ) - { - typedef typename TypeInfo::Type Type; - typedef typename JSToNative::ResultType NativeHandle; - NativeHandle self = CastFromJS( info.This() ); - return self - ? CastToJS( (self->*Getter)() ) - : Toss( StringBuffer() << "Native member property getter '" - << property << "' could not access native This object!" ); - } - }; - - /** - Overload for const native getter functions. - */ - template ::FunctionType Getter> - struct ConstMethodToGetter : AccessorGetterType - { - inline static v8::Handle Get( v8::Local< v8::String > property, const v8::AccessorInfo & info ) - { - typedef typename TypeInfo::Type Type; - typedef typename JSToNative::ResultType NativeHandle; - NativeHandle const self = CastFromJS( info.This() ); - return self - ? CastToJS( (self->*Getter)() ) - : Toss( (StringBuffer() << "Native member property getter '" - << property << "' could not access native This object!").toError() ) - ; - } - }; - - /** - Implements v8::AccessorSetter interface to proxy a JS - member property through a native member setter function. - - This function can be used as the setter parameter to - v8::ObjectTemplate::SetAccessor(). - - Sig must be a function-pointer-style type and Getter must - be a T member function of that type. The function must be - capable of being called with only 1 argument (either - because it only accepts 1 or has defaults for the others), - and its return value is discarded (not converted to v8) - because that's how v8's native setters work. - - Exceptions thrown by the underlying function are - translated to JS exceptions. - - FIXME: code is 100% identical to ConstMethodToSetter except - for FunctionType typedef. Consolidate them in a base class. - */ - template ::FunctionType Setter> - struct MethodToSetter : AccessorSetterType - { - static void Set(v8::Local< v8::String > property, v8::Local< v8::Value > value, const v8::AccessorInfo &info) - { - typedef typename TypeInfo::Type Type; - typedef typename JSToNative::ResultType NativeHandle; - NativeHandle self = CastFromJS( info.This() ); - if( ! self ) - { - Toss( StringBuffer() << "Native member property setter '" - << property << "' could not access native This object!" ); - } - else - { - - typedef typename sl::At< 0, Signature >::Type ArgT; - (self->*Setter)( CastFromJS( value ) ); - } - return; - } - }; - - /** - Const-method equivalent of MethodToSetter. - - FIXME: code is 100% identical to ConstMethodToSetter except - for FunctionType typedef. Consolidate them in a base class. - */ - template ::FunctionType Setter> - struct ConstMethodToSetter : AccessorSetterType - { - static void Set(v8::Local< v8::String > property, v8::Local< v8::Value > value, const v8::AccessorInfo &info) - { - typedef typename TypeInfo::Type Type; - typedef typename JSToNative::ResultType NativeHandle; - NativeHandle self = CastFromJS( info.This() ); - if( ! self ) - { - Toss( StringBuffer() << "Native member property setter '" - << property << "' could not access native This object!" ); - } - else - { - typedef typename sl::At< 0, Signature >::Type ArgT; - (self->*Setter)( CastFromJS( value ) ); - } - } - }; - - - /** - Similar to FunctionToGetter but uses a functor as a getter. - This is rarely useful, since the functor has no direct access - to any application state (unless that is static/shared within - the Ftor class). - - Ftor must be a functor. Sig must be a signature matching a const - Ftor::operator() implementation. CastToJS(Signature::ReturnType) - must be legal. - - The signature's return type may not be void (this is a getter, - and getters don't return void). - */ - template - struct FunctorToGetter - { - inline static v8::Handle Get( v8::Local< v8::String > property, const v8::AccessorInfo & info ) - { - //const static Ftor f(); - return CastToJS(Ftor()()); - } - }; - - /** - The setter counterpart of FunctorToGetter. - - Ftor must be a functor which accepts 1 arguments. - Sig must be a signature matching a Ftor::operator() - implementation. - - The return value of Ftor::operator() is not evaluated, so it may be - void or any non-convertible type. It is semantically illegal to bind - a setter which return resources allocated by the setter, if those - resources are passed to the caller. In such a case, each access - _will_ leak memory. But nobody returns allocated memory from a - setter, right? - - CastFromJS() must be legal, where ArgType1 - is sl::At<0, Signature >::Type. - */ - template - struct FunctorToSetter - { - inline static void Set(v8::Local< v8::String > property, v8::Local< v8::Value > value, const v8::AccessorInfo &info) - { - typedef typename sl::At< 0, Signature >::Type ArgT; - Ftor()( CastFromJS( value ) ); - } - }; - - /** - SetterCatcher is the AccessorSetter equivalent of InCaCatcher, and - is functionality identical except that its 4th template parameter - must be-a AccessorSetterType instead of an InCa type. - */ - template < typename ExceptionT, - typename SigGetMsg, - typename ConstMethodSignature::FunctionType Getter, - typename SetterT, - bool PropagateOtherExceptions = false - > - struct SetterCatcher : AccessorSetterType - { - static void Set(v8::Local< v8::String > property, v8::Local< v8::Value > value, const v8::AccessorInfo &info) - { - try - { - SetterT::Set( property, value, info ); - } - catch( ExceptionT const & e2 ) - { - Toss((e2.*Getter)()); - } - catch( ExceptionT const * e2 ) - { - Toss((e2->*Getter)()); - } - catch(...) - { - if( PropagateOtherExceptions ) throw; - else Toss("Unknown native exception thrown!"); - } - } - }; - - /** - A convenience form of SetterCatcher which catches std::exception - and subtyes. See InCaCatcher_std for full details - this type is - identical except that its first template parameter must be-a - AccessorSetterType instead of InCa type. - */ - template < - typename SetterT, - typename ConcreteException = std::exception, - bool PropagateOtherExceptions = !tmp::SameType< std::exception, ConcreteException >::Value - > - struct SetterCatcher_std : - SetterCatcher - {}; - - /** - GetterCatcher is the AccessorSetter equivalent of InCaCatcher, and - is functionality identical except that its 4th template parameter - must be-a AccessorGetterType instead of an InCa type. - */ - template < typename ExceptionT, - typename SigGetMsg, - typename ConstMethodSignature::FunctionType Getter, - typename GetterT, - bool PropagateOtherExceptions = false - > - struct GetterCatcher : AccessorGetterType - { - static v8::Handle Get( v8::Local< v8::String > property, const v8::AccessorInfo & info ) - { - try - { - return GetterT::Get( property, info ); - } - catch( ExceptionT const & e2 ) - { - return Toss(CastToJS((e2.*Getter)())); - } - catch( ExceptionT const * e2 ) - { - return Toss(CastToJS((e2->*Getter)())); - } - catch(...) - { - if( PropagateOtherExceptions ) throw; - else return Toss("Unknown native exception thrown!"); - } - } - }; - - /** - A convenience form of GetterCatcher which catches std::exception - and subtyes. See InCaCatcher_std for full details - this type is - identical except that its first template parameter must be-a - AccessorGetterType instead of InCa type. - */ - template < - typename GetterT, - typename ConcreteException = std::exception, - bool PropagateOtherExceptions = !tmp::SameType< std::exception, ConcreteException >::Value - > - struct GetterCatcher_std : - GetterCatcher - {}; - - - /** - AccessAdder is a convenience class for use when applying several - (or more) accessor bindings to a prototype object. - - Example: - - @code - AccessorAdder acc(myPrototype); - acc("foo", MemberToGetter(), - MemberToSetter()) - ("bar", ConstMethodToGetter(), - MethodToSetter()) - ... - ; - @endcode - */ - class AccessorAdder - { - private: - v8::Handle const & proto; - - /** A "null" setter which does nothing. Used only as default - argument to operator(). Its Set() is not actually used - but this type is used as a placeholder for a NULL - v8::AccessorSetter. - */ - struct NullSetter - { - /** The v8::AccessorSetter() interface. */ - static void Set(v8::Local< v8::String > property, v8::Local< v8::Value > value, const v8::AccessorInfo &info) - { - } - }; - public: - /** - Initializes this object so that calls to operator() will - apply to p. p must out-live this object. More specifically, - operator() must not be called after p has been destroyed. - */ - explicit AccessorAdder( v8::Handle const & p ) - : proto(p) - {} - AccessorAdder const & operator()( char const * name, - v8::AccessorGetter g, - v8::AccessorSetter s = NULL, - v8::Handle< v8::Value > data=v8::Handle< v8::Value >(), - v8::AccessControl settings=v8::DEFAULT, - v8::PropertyAttribute attribute=v8::None) const - { - proto->SetAccessor(v8::String::New(name), g, s, data, settings, attribute); - return *this; - } - /** - Adds GetterT::Get and SetterT::Set as accessors for the - given property in the prototype object. - - GetterT must be-a AccessorGetterType. SetterT must be-a - AccessorSetterType. Note that their values are not used, - but GetterT::Get and SetterT::Set are used - directly. The objects are only passed in to keep the - client from having to specify them as template - parameters (which is clumsy for operator()), as their - types can be deduced. - - The 3rd and higher arguments are as documented (or not!) - for v8::ObjectTemplate::SetAccessor(). - - Returns this object, for chaining calls. - */ - template - AccessorAdder const & operator()( char const * name, - GetterT const &, - SetterT const & = NullSetter(), - v8::Handle< v8::Value > data=v8::Handle< v8::Value >(), - v8::AccessControl settings=v8::DEFAULT, - v8::PropertyAttribute attribute=v8::None) const - { - // jump through a small hoop to ensure identical semantics vis-a-vis - // the other overload. - return this->operator()( name, GetterT::Get, - tmp::SameType::Value ? NULL : SetterT::Set, - data, settings, attribute); - } - }; - -#if 0 /* i'm still undecided on the in-class naming conventions here... */ - /** - ClassAccessor provides a slight simplification for cases - where several different members/methods of a given bound - class (T) need to be bound to v8. It wraps the following - classes so that clients can use them one fewer template - parameters: - - MemberToGetter, MemberToSetter, MethodToGetter, MethodToSetter, - ConstMethodToGetter, ConstMethodToSetter - - Example: - - @code - typedef ClassAccessor CA; - v8::AccessorGetter get; - - get = MemberToGetter::Get - // is equivalent to: - get = CA::MemGet::Set - @endcode - - Its only real benefit is saving a bit of typing when several T - member/method bindings are made and T's real type name is longer - than 'T'. e.g. it gets tedious to repeatedly type - MyExceedinglyLongClassName in method/member-binding templates. - (Function-local typedefs help.) - */ - template - struct ClassAccessor - { - template - struct MemGet : MemberToGetter {}; - template - struct MemSet : MemberToSetter {}; - template ::FunctionType Getter> - struct MethGet : MethodToGetter {}; - template ::FunctionType Getter> - struct CMethGet : ConstMethodToGetter {}; - template ::FunctionType Setter> - struct MethSet : MethodToSetter {}; - template ::FunctionType Setter> - struct CMethSet : ConstMethodToSetter {}; - }; -#endif /* ClassAccessor */ - -} // namespaces -/** LICENSE - - This software's source code, including accompanying documentation and - demonstration applications, are licensed under the following - conditions... - - The author (Stephan G. Beal [http://wanderinghorse.net/home/stephan/]) - explicitly disclaims copyright in all jurisdictions which recognize - such a disclaimer. In such jurisdictions, this software is released - into the Public Domain. - - In jurisdictions which do not recognize Public Domain property - (e.g. Germany as of 2011), this software is Copyright (c) 2011 - by Stephan G. Beal, and is released under the terms of the MIT License - (see below). - - In jurisdictions which recognize Public Domain property, the user of - this software may choose to accept it either as 1) Public Domain, 2) - under the conditions of the MIT License (see below), or 3) under the - terms of dual Public Domain/MIT License conditions described here, as - they choose. - - The MIT License is about as close to Public Domain as a license can - get, and is described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - - The full text of the MIT License follows: - - -- - Copyright (c) 2011 Stephan G. Beal (http://wanderinghorse.net/home/stephan/) - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - --END OF MIT LICENSE-- - - For purposes of the above license, the term "Software" includes - documentation and demonstration source code which accompanies - this software. ("Accompanies" = is contained in the Software's - primary public source code repository.) - -*/ -#endif /* CODE_GOOGLE_COM_P_V8_CONVERT_PROPERTIES_HPP_INCLUDED */ diff --git a/vendor/libv8-convert/cvv8/signature.hpp b/vendor/libv8-convert/cvv8/signature.hpp deleted file mode 100644 index 4961d7039..000000000 --- a/vendor/libv8-convert/cvv8/signature.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#if !defined(WANDERINGHORSE_NET_SIGNATURE_HPP_INCLUDED) -#define WANDERINGHORSE_NET_SIGNATURE_HPP_INCLUDED 1 - - -namespace cvv8 { -#include "detail/signature_core.hpp" -#include "detail/signature_generated.hpp" -} -/** LICENSE - - This software's source code, including accompanying documentation and - demonstration applications, are licensed under the following - conditions... - - The author (Stephan G. Beal [http://wanderinghorse.net/home/stephan/]) - explicitly disclaims copyright in all jurisdictions which recognize - such a disclaimer. In such jurisdictions, this software is released - into the Public Domain. - - In jurisdictions which do not recognize Public Domain property - (e.g. Germany as of 2011), this software is Copyright (c) 2011 - by Stephan G. Beal, and is released under the terms of the MIT License - (see below). - - In jurisdictions which recognize Public Domain property, the user of - this software may choose to accept it either as 1) Public Domain, 2) - under the conditions of the MIT License (see below), or 3) under the - terms of dual Public Domain/MIT License conditions described here, as - they choose. - - The MIT License is about as close to Public Domain as a license can - get, and is described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - - The full text of the MIT License follows: - - -- - Copyright (c) 2011 Stephan G. Beal (http://wanderinghorse.net/home/stephan/) - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - --END OF MIT LICENSE-- - - For purposes of the above license, the term "Software" includes - documentation and demonstration source code which accompanies - this software. ("Accompanies" = is contained in the Software's - primary public source code repository.) - -*/ -#endif /* WANDERINGHORSE_NET_SIGNATURE_HPP_INCLUDED */ diff --git a/vendor/libv8-convert/cvv8/v8-convert.hpp b/vendor/libv8-convert/cvv8/v8-convert.hpp deleted file mode 100644 index 1ee91d73e..000000000 --- a/vendor/libv8-convert/cvv8/v8-convert.hpp +++ /dev/null @@ -1,169 +0,0 @@ -#if !defined(CODE_GOOGLE_COM_P_V8_CONVERT_V8_CONVERT_HPP_INCLUDED) -#define CODE_GOOGLE_COM_P_V8_CONVERT_V8_CONVERT_HPP_INCLUDED 1 - -// Doxygen REFUSES to use this block as namespace docs: @namespace cvv8 -/** @mainpage libv8-convert (cvv8) - -The cvv8 namespace (formerly v8::convert) houses APIs for handling the -following: - -- Converting between v8 Value handles and "native types" using generic -interface. This allows us to write generic algorithms which convert -between JS/C++ without having to know the exact types we're dealing -with. The basic POD types and some STL types are supported out of the -box and plugging in one's own types is normally quite simple. - -- Converting free- and member functions into v8::InvocationCallback -functions. These generated functions convert the JavaScript-originated -function arguments into native counterparts, forward the data to the -original native function, and convert the return values back to -something JS can use. - -Those two core features give us all we need in order to be able to -bind near-arbitrary C/C++ functions with JavaScript (where calling -conventions and type conversions allow us to do so). For cases where -the "automatic" function-to-InvocationCallback conversions are not -suitable, the type-conversion API can simplify the implementation of -custom v8::InvocationCallback functions. - -All of the conversions are compile-time typesafe where possible and -fail gracefully when such a determination can only be made at runtime. - -This code originated as the core-most component of the v8-juice -library (http://code.google.com/p/v8-juice). After a couple years -i felt compelled to refactor it into a toolkit usable by arbitrary -v8-using clients, doing a bit of cleanup along the way. The eventuall -intention is that this code will replace the v8::juice::convert -code. - -Author: Stephan Beal (http://wanderinghorse.net/home/stephan/) - -License: Dual MIT/Public Domain - -Project home page: http://code.google.com/p/v8-juice/wiki/V8Convert - -The most important functions and types, from a user's perspective, -include: - -Converting types: - -- cvv8::CastToJS() -- cvv8::CastFromJS() - -Implementing custom conversions: - -- cvv8::NativeToJS -- cvv8::JSToNative - -Converting functions to v8::InvocationCallback: - -- cvv8::FunctionToInCa -- cvv8::MethodToInCa -- cvv8::ConstMethodToInCa -- cvv8::ToInCa -- cvv8::FunctorToInCa -- cvv8::PredicatedInCa and cvv8::PredicatedInCaDispatcher - -Binding JS properties to native properties, functions, methods, or -functors: - -- cvv8::FunctionToGetter, cvv8::FunctionToSetter -- cvv8::MethodToGetter, cvv8::MethodToSetter -- cvv8::ConstMethodToGetter, cvv8::ConstMethodToSetter -- cvv8::FunctorToGetter, cvv8::FunctorToSetter - -Other utilities: - -- cvv8::CtorForwarder and cvv8::CtorArityDispatcher -- cvv8::ClassCreator simplifies binding of C++ classes with v8. -- cvv8::FunctionTo converts functions to ... -- cvv8::MethodTo converts methods to ... -- cvv8::FunctorTo converts functors to ... -- cvv8::VarTo converts variables to ... -- cvv8::CallForwarder forwards native arguments to JS functions. -- The tmp and sl namespaces hold various template metaprogramming bits. -- ... there's more ... - -Most of the code in this library are internal template specializations -which take care of the dirty work. Typical clients won't typically need -more than what's listed above. - -A core rule of this library is "if it ain't documented, don't use -it." All public API members which are intended for client-side use -are documented. Some one-line proxies whose purpose is either very -obvious, exist only for template type resolution reasons, or -are strictly internal are not necessarily documented. - -*/ -namespace cvv8 { -} - -#include "convert.hpp" -#include "invocable.hpp" -#include "arguments.hpp" -#include "ClassCreator.hpp" -#include "properties.hpp" -#include "XTo.hpp" -/** LICENSE - - This software's source code, including accompanying documentation and - demonstration applications, are licensed under the following - conditions... - - The author (Stephan G. Beal [http://wanderinghorse.net/home/stephan/]) - explicitly disclaims copyright in all jurisdictions which recognize - such a disclaimer. In such jurisdictions, this software is released - into the Public Domain. - - In jurisdictions which do not recognize Public Domain property - (e.g. Germany as of 2011), this software is Copyright (c) 2011 - by Stephan G. Beal, and is released under the terms of the MIT License - (see below). - - In jurisdictions which recognize Public Domain property, the user of - this software may choose to accept it either as 1) Public Domain, 2) - under the conditions of the MIT License (see below), or 3) under the - terms of dual Public Domain/MIT License conditions described here, as - they choose. - - The MIT License is about as close to Public Domain as a license can - get, and is described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - - The full text of the MIT License follows: - - -- - Copyright (c) 2011 Stephan G. Beal (http://wanderinghorse.net/home/stephan/) - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - --END OF MIT LICENSE-- - - For purposes of the above license, the term "Software" includes - documentation and demonstration source code which accompanies - this software. ("Accompanies" = is contained in the Software's - primary public source code repository.) - -*/ - -#endif /* CODE_GOOGLE_COM_P_V8_CONVERT_V8_CONVERT_HPP_INCLUDED */ diff --git a/vendor/naturaldocs/Config/Languages.txt b/vendor/naturaldocs/Config/Languages.txt deleted file mode 100644 index 28adf6186..000000000 --- a/vendor/naturaldocs/Config/Languages.txt +++ /dev/null @@ -1,286 +0,0 @@ -Format: 1.51 - -# This is the main Natural Docs languages file. If you change anything here, -# it will apply to EVERY PROJECT you use Natural Docs on. If you'd like to -# change something for just one project, edit the Languages.txt in its project -# directory instead. - - -#------------------------------------------------------------------------------- -# SYNTAX: -# -# Unlike other Natural Docs configuration files, in this file all comments -# MUST be alone on a line. Some languages deal with the # character, so you -# cannot put comments on the same line as content. -# -# Also, all lists are separated with spaces, not commas, again because some -# languages may need to use them. -# -# Language: [name] -# Defines a new language. Its name can use any characters. -# -# The language Shebang Script is special. It's entry is only used for -# extensions, and files with those extensions have their shebang (#!) lines -# read to determine the real language of the file. Extensionless files are -# always treated this way. -# -# The language Text File is also special. It's treated as one big comment -# so you can put Natural Docs content in them without special symbols. Also, -# if you don't specify a package separator, ignored prefixes, or enum value -# behavior, it will copy those settings from the language that is used most -# in the source tree. -# -# Extensions: [extension] [extension] ... -# Defines the file extensions of the language's source files. You can use * -# to mean any undefined extension. -# -# Shebang Strings: [string] [string] ... -# Defines a list of strings that can appear in the shebang (#!) line to -# designate that it's part of the language. -# -# Ignore Prefixes in Index: [prefix] [prefix] ... -# Ignore [Topic Type] Prefixes in Index: [prefix] [prefix] ... -# Specifies prefixes that should be ignored when sorting symbols in an -# index. Can be specified in general or for a specific topic type. -# -#------------------------------------------------------------------------------ -# For basic language support only: -# -# Line Comments: [symbol] [symbol] ... -# Defines a space-separated list of symbols that are used for line comments, -# if any. -# -# Block Comments: [opening sym] [closing sym] [opening sym] [closing sym] ... -# Defines a space-separated list of symbol pairs that are used for block -# comments, if any. -# -# Package Separator: [symbol] -# Defines the default package separator symbol. The default is a dot. -# -# [Topic Type] Prototype Enders: [symbol] [symbol] ... -# When defined, Natural Docs will attempt to get a prototype from the code -# immediately following the topic type. It stops when it reaches one of -# these symbols. Use \n for line breaks. -# -# Line Extender: [symbol] -# Defines the symbol that allows a prototype to span multiple lines if -# normally a line break would end it. -# -# Enum Values: [global|under type|under parent] -# Defines how enum values are referenced. The default is global. -# global - Values are always global, referenced as 'value'. -# under type - Values are under the enum type, referenced as -# 'package.enum.value'. -# under parent - Values are under the enum's parent, referenced as -# 'package.value'. -# -# Perl Package: [perl package] -# Specifies the Perl package used to fine-tune the language behavior in ways -# too complex to do in this file. -# -#------------------------------------------------------------------------------ -# For full language support only: -# -# Full Language Support: [perl package] -# Specifies the Perl package that has the parsing routines necessary for full -# language support. -# -#------------------------------------------------------------------------------- - -# The following languages MUST be defined in this file: -# -# Text File, Shebang Script - -# If you add a language that you think would be useful to other developers -# and should be included in Natural Docs by default, please e-mail it to -# languages [at] naturaldocs [dot] org. - - -Language: Text File - - Extension: txt - - -Language: Shebang Script - - Extension: cgi - - -Language: C/C++ - - Extensions: c cpp h hpp cxx hxx - Ignore Function Prefix in Index: ~ - Line Comment: // - Block Comment: /* */ - Package Separator: :: - Enum Values: Under parent - Class Prototype Enders: ; { - Function Prototype Enders: ; { - Variable Prototype Enders: ; = - - -Language: C# - - Extension: cs - Ignore Prefix in Index: @ - Full Language Support: NaturalDocs::Languages::CSharp - - -Language: Java - - Extension: java - Line Comment: // - Block Comment: /* */ - Enum Values: Under type - Function Prototype Ender: { - Variable Prototype Enders: ; = - - -Language: JavaScript - - Extension: js - Line Comment: // - Block Comment: /* */ - Enum Values: Under type - Function Prototype Ender: { - Variable Prototype Enders: ; = , } - - -Language: Perl - - Extensions: pl pm - Shebang String: perl - Ignore Variable Prefixes in Index: $ @ % * - Full Language Support: NaturalDocs::Languages::Perl - - -Language: Python - - Extension: py - Shebang String: python - Line Comment: # - Function Prototype Ender: : - Variable Prototype Ender: = - Line Extender: \ - - -Language: PHP - - Extensions: inc php php3 php4 phtml - Shebang String: php - Ignore Variable Prefix in Index: $ - Line Comments: // # - Block Comment: /* */ - Function Prototype Enders: ; { - Variable Prototype Enders: ; = - - -Language: SQL - - Extension: sql - Line Comment: -- - Block Comment: /* */ - Enum Values: Global - Function Prototype Enders: , ; ) as As AS is Is IS - Variable Prototype Enders: , ; ) := default Default DEFAULT - Database Index Prototype Enders: , ; ) - Database Trigger Prototype Enders: begin Begin BEGIN as As AS - Perl Package: NaturalDocs::Languages::PLSQL - - -Language: Visual Basic - - Extensions: vb vbs bas cls frm - Line Comment: ' - Enum Values: Under type - Function Prototype Ender: \n - Variable Prototype Enders: \n = - Line Extender: _ - - -Language: Pascal - - Extension: pas - Line Comment: // - Block Comments: { } (* *) - Function Prototype Ender: ; - Variable Prototype Enders: ; = - Perl Package: NaturalDocs::Languages::Pascal - - -Language: Assembly - - Extension: asm - Line Comment: ; - Variable Prototype Ender: \n - Line Extender: \ - - -Language: Ada - - Extensions: ada ads adb - Line Comment: -- - Function Prototype Enders: ; is Is IS - Variable Prototype Enders: ; := - Perl Package: NaturalDocs::Languages::Ada - - -Language: Tcl - - Extensions: tcl exp - Shebang Strings: tclsh wish expect - Line Comment: # - Package Separator: :: - Function Prototype Enders: ; { - Variable Prototype Enders: ; \n - Line Extender: \ - Perl Package: NaturalDocs::Languages::Tcl - - -Language: Ruby - - Extension: rb - Shebang String: ruby - Ignore Variable Prefixes in Index: $ @ @@ - Line Comment: # - Enum Values: Under parent - Function Prototype Enders: ; \n - Variable Prototype Enders: ; \n = - Line Extender: \ - - -Language: Makefile - - Extensions: mk mak make - Line Comment: # - - -Language: ActionScript - - Extensions: as mxml - Full Language Support: NaturalDocs::Languages::ActionScript - - -Language: ColdFusion - - Extensions: cfm cfml cfc - Line Comment: // - Block Comments: /* */ - Function Prototype Enders: { < - - -Language: R - - Extension: r - Line Comment: # - Function Prototype Enders: { ; - Variable Prototype Enders: <- = ; \n - - -Language: Fortran - - Extensions: f90 f95 f03 - Line Comment: ! - Function Prototype Ender: \n - Variable Prototype Enders: \n = => - Line Extender: & diff --git a/vendor/naturaldocs/Config/Topics.txt b/vendor/naturaldocs/Config/Topics.txt deleted file mode 100644 index 9a10469b6..000000000 --- a/vendor/naturaldocs/Config/Topics.txt +++ /dev/null @@ -1,382 +0,0 @@ -Format: 1.51 - -# This is the main Natural Docs topics file. If you change anything here, it -# will apply to EVERY PROJECT you use Natural Docs on. If you'd like to -# change something for just one project, edit the Topics.txt in its project -# directory instead. - - -#------------------------------------------------------------------------------- -# SYNTAX: -# -# Topic Type: [name] -# Creates a new topic type. Each type gets its own index and behavior -# settings. Its name can have letters, numbers, spaces, and these -# charaters: - / . ' -# -# The Enumeration type is special. It's indexed with Types but its members -# are indexed with Constants according to the rules in Languages.txt. -# -# Plural: [name] -# Sets the plural name of the topic type, if different. -# -# Keywords: -# [keyword] -# [keyword], [plural keyword] -# ... -# Defines a list of keywords for the topic type. They may only contain -# letters, numbers, and spaces and are not case sensitive. Plural keywords -# are used for list topics. -# -# Index: [yes|no] -# Whether the topics get their own index. Defaults to yes. Everything is -# included in the general index regardless of this setting. -# -# Scope: [normal|start|end|always global] -# How the topics affects scope. Defaults to normal. -# normal - Topics stay within the current scope. -# start - Topics start a new scope for all the topics beneath it, -# like class topics. -# end - Topics reset the scope back to global for all the topics -# beneath it. -# always global - Topics are defined as global, but do not change the scope -# for any other topics. -# -# Class Hierarchy: [yes|no] -# Whether the topics are part of the class hierarchy. Defaults to no. -# -# Page Title If First: [yes|no] -# Whether the topic's title becomes the page title if it's the first one in -# a file. Defaults to no. -# -# Break Lists: [yes|no] -# Whether list topics should be broken into individual topics in the output. -# Defaults to no. -# -# Can Group With: [type], [type], ... -# Defines a list of topic types that this one can possibly be grouped with. -# Defaults to none. -#------------------------------------------------------------------------------- - -# The following topics MUST be defined in this file: -# -# Generic, Class, Interface, Section, File, Group, Function, Variable, -# Property, Type, Constant, Enumeration, Event, Delegate - -# If you add something that you think would be useful to other developers -# and should be included in Natural Docs by default, please e-mail it to -# topics [at] naturaldocs [dot] org. - - -Topic Type: Generic - - Index: No - Keywords: - topic, topics - about, list - - -Topic Type: Class - - Plural: Classes - Scope: Start - Class Hierarchy: Yes - Page Title If First: Yes - Can Group With: Interfaces - - Keywords: - class, classes - structure, structures - struct, structs - package, packages - namespace, namespaces - - -Topic Type: Interface - - Plural: Interfaces - Scope: Start - Class Hierarchy: Yes - Page Title If First: Yes - Can Group With: Classes - - Keywords: - interface, interfaces - - -Topic Type: Section - - Plural: Sections - Index: No - Scope: End - Page Title If First: Yes - - Keywords: - section - title - - -Topic Type: File - - Plural: Files - Scope: Always global - Page Title If First: Yes - - Keywords: - file, files - program, programs - script, scripts - document, documents - doc, docs - header, headers - - -Topic Type: Group - - Plural: Groups - Index: No - - Keywords: - group - - -Topic Type: Function - - Plural: Functions - Break Lists: Yes - Can Group With: Properties - - Keywords: - function, functions - func, funcs - procedure, procedures - proc, procs - routine, routines - subroutine, subroutines - sub, subs - method, methods - callback, callbacks - constructor, constructors - destructor, destructors - operator, operators - - -Topic Type: Variable - - Plural: Variables - Can Group With: Types, Constants, Macros, Enumerations - - Keywords: - variable, variables - var, vars - integer, integers - int, ints - uint, uints - long, longs - ulong, ulongs - short, shorts - ushort, ushorts - byte, bytes - ubyte, ubytes - sbyte, sbytes - float, floats - double, doubles - real, reals - decimal, decimals - scalar, scalars - array, arrays - arrayref, arrayrefs - hash, hashes - hashref, hashrefs - bool, bools - boolean, booleans - flag, flags - bit, bits - bitfield, bitfields - field, fields - pointer, pointers - ptr, ptrs - reference, references - ref, refs - object, objects - obj, objs - character, characters - wcharacter, wcharacters - char, chars - wchar, wchars - string, strings - wstring, wstrings - str, strs - wstr, wstrs - handle, handles - - -Topic Type: Property - - Plural: Properties - Can Group With: Functions - - Keywords: - property, properties - prop, props - - -Topic Type: Type - - Plural: Types - Can Group With: Variables, Constants, Macros, Enumerations - - Keywords: - type, types - typedef, typedefs - - -Topic Type: Constant - - Plural: Constants - Can Group With: Variables, Types, Macros, Enumerations - - Keywords: - constant, constants - const, consts - - -Topic Type: Enumeration - - Plural: Enumerations - Index: No - Can Group With: Variables, Types, Macros, Constants - - Keywords: - enum, enums - enumeration, enumerations - - -Topic Type: Event - - Plural: Events - Keywords: - event, events - - -Topic Type: Delegate - - Plural: Delegates - Keywords: - delegate, delegates - - -Topic Type: Macro - - Plural: Macros - Can Group With: Variables, Types, Constants - - Keywords: - define, defines - def, defs - macro, macros - - -Topic Type: Database - - Plural: Databases - Page Title If First: Yes - - Keywords: - database, databases - db, dbs - - -Topic Type: Database Table - - Plural: Database Tables - Scope: Start - Page Title If First: Yes - - Keywords: - table, tables - database table, database tables - databasetable, databasetables - db table, db tables - dbtable, dbtables - - -Topic Type: Database View - - Plural: Database Views - Scope: Start - Page Title If First: Yes - - Keywords: - view, views - database view, database views - databaseview, databaseviews - db view, db views - dbview, dbviews - - -Topic Type: Database Index - - Plural: Database Indexes - Keywords: - index, indexes - index, indices - database index, database indexes - database index, database indices - databaseindex, databaseindexes - databaseindex, databaseindices - db index, db indexes - db index, db indices - dbindex, dbindexes - dbindex, dbindices - key, keys - database key, database keys - databasekey, databasekeys - db key, db keys - dbkey, dbkeys - primary key, primary keys - primarykey, primarykeys - database primary key, database primary keys - databaseprimarykey, databaseprimarykeys - db primary key, db primary keys - dbprimarykey, dbprimarykeys - - -Topic Type: Database Cursor - - Plural: Database Cursors - Keywords: - cursor, cursors - database cursor, database cursors - databasecursor, databasecursors - db cursor, db cursors - dbcursor, dbcursors - - -Topic Type: Database Trigger - - Plural: Database Triggers - Keywords: - trigger, triggers - database trigger, database triggers - databasetrigger, databasetriggers - db trigger, db triggers - dbtrigger, dbtriggers - - -Topic Type: Cookie - - Plural: Cookies - Scope: Always global - - Keywords: - cookie, cookies - - -Topic Type: Build Target - - Plural: Build Targets - Keywords: - target, targets - build target, build targets - buildtarget, buildtargets diff --git a/vendor/naturaldocs/Help/customizinglanguages.html b/vendor/naturaldocs/Help/customizinglanguages.html deleted file mode 100644 index 0b579d96c..000000000 --- a/vendor/naturaldocs/Help/customizinglanguages.html +++ /dev/null @@ -1,52 +0,0 @@ - - -Customizing Natural Docs Languages - - - -
Natural Docs
Customizing
Organizing the MenuCSS StylesTopics and KeywordsLanguages, Indexes,
and Prototypes
Customizing Languages
Languages.txt

Natural Docs has two files called Languages.txt: one in its Config directory, and one in your project directory.  These control the language, index prefix, and prototype features of Natural Docs.

You should edit the one in your project directory whenever possible.  It keeps your changes separate and easier to manage, plus you don’t have to reapply them whenever you upgrade.  Editing the one in Natural Docs’ Config directory would be better only if you’re using Natural Docs with a lot of projects and would like the changes to apply everywhere.

Note that unlike other Natural Docs configuration files, comments can only appear on their own lines.  They cannot appear after something else on a line because settings may need to use the # symbol.  Also, all lists are space-separated instead of comma-separated, again because some settings may need to use the comma symbol.

File Extensions

If Natural Docs doesn’t recognize a file extension you use for your code, it’s not a problem.  You can alter the language definition from your project file to add them.

Alter Language: [your language]
-   Add Extensions: cxx hxx

On the other hand, if it’s scanning some files you don’t want it to scan, you can exclude extensions as well.  Just add this to the top of your file:

Ignore Extensions: c cpp

In this example, Natural Docs will ignore C++ source files, thus only scanning the headers.

Adding Languages

You can add basic language support for any programming language just by editing these configuration files.  Here are the most important settings:

Language: Fictional
-
-   Extensions: fsrc fhdr
-   Shebang Strings: fictional
-   Line Comment: //
-   Block Comment: /* */
-   Package Separator: ::

This tells Natural Docs that any files with the .fsrc or .fhdr extensions are part of our fictional programming language.  Also, any .cgi or extensionless files that have “fictional” in the shebang (#!) line are part of it as well.  Line comments start with // and block comments appear between /* and */.  The default package separator is ::.  Not too hard, huh?

You can also add settings to ignore prefixes in the index and detect prototypes, but those are dealt with in their own sections on this page.

Prototypes

So you’ve added a new language and want to detect prototypes.  Or perhaps you added a custom topic type and want to detect prototypes for that as well.  Here’s an example of the properties you need:

Function Prototype Enders: ; {
-Variable Prototype Enders: ; =

The algorithm for finding prototypes is very simple, yet it works really well in practice.  All the code following the comment is grabbed until it reaches an ender symbol or another comment.  Ender symbols appearing inside parenthesis, brackets, braces, or angle brackets don’t count.  If it reaches an ender symbol and somewhere in that code is the topic title, the code is accepted as the prototype.

So in the example above, variables end at semicolons (the end of the declaration) or equal signs (the default value expression, which we don’t want to include.)  Since the Natural Docs comment for the variable should have appeared right before the definition, that leaves us with the name and type.  Functions are handled similarly: they end at a semicolon (the end of a predeclaration) or an opening brace (the beginning of the body) leaving us with the name, parameters, and return type.

You can do this with any topic type, including custom ones.  Any prototypes that look like they have parameters will be formatted as such automatically.

Line Breaks

For some languages, line breaks are significant.  To have them end a prototype, use \n.  If it has an extender symbol that allows the code to continue on the next line, you can specify that as well.

Function Prototype Ender: \n
-Variable Prototype Ender: \n =
-Line Extender: _
Colors

If you’re collecting prototypes for a custom topic type, they will not automatically get their own background color like the other types have.  You have to define it via CSS.

Index Prefixes

Natural Docs has the ability to ignore prefixes in the indexes.  This is necessary because in certain languages, variables are prefixed with $ or other symbols and we don’t want them to get all grouped together under the symbols heading.  Instead, they appear in the sidebar and are sorted as if they’re not there.

A
 AddProperty, SomeClass
$amount
 Average

However, we can take advantage of this simply to get around coding conventions.  Suppose you prefix all your class names with C.  They’d all form one gigantic group under C in the index.  If you want, you can have it ignored so CCat, CDog, and CMouse get filed under C, D, and M instead.  Just add this to your languages file:

Alter Language: [your language]
-   Add Ignored Class Prefix in Index: C

Now C is ignored in your indexes:

A
CAccount
CAccountHolder
 AddProperty, SomeClass
$amount
 Average

You can include any number of prefixes and can do this for any topic type.  So if you have a bunch of functions that start with COM_ and DB_, you can ignore them too:

Alter Language: [your language]
-   Add Ignored Class Prefix in Index: C
-   Add Ignored Function Prefixes in Index: COM_ DB_
Special Languages

There are two languages with special properties: Shebang Script and Text File.

Shebang Script allows you to define the file extensions where the language is really determined by the shebang (#!) line within it.  For example, .cgi files.  If Natural Docs finds a .cgi file, it sees that it’s a Shebang Script so it opens it up to parse it’s shebang line.  It then searches it for substrings defined by other languages’ Shebang String settings to find out what language it really is.  Files with no extension are always treated this way.

With Text File, the entire file is treated like a comment.  There are no comment symbols required, you can just put Natural Docs content there in plain text.  The most important setting is Extensions.

However, since it is possible to document classes, functions, etc. in text files, they also have their own Package Separator and Ignored [type] Prefixes in Index settings.  To make things easier on you, by default it copies these settings from whichever language has the most source files in your project.  You can override this by manually setting them, but you shouldn’t need to.

Syntax Reference

Unlike other Natural Docs configuration files, comments can only appear on their own lines.  They cannot appear after something else on a line because settings may need to use the # symbol.  Likewise, lists are separated with spaces instead of commas because commas themselves may need to appear on the list.

Singular and plural forms are generally both supported, so you can write Extension or Extensions.  It doesn’t matter if they match how many items are set.  Also, you can use either Ignore or Ignored.

Ignore Extensions: [extension] [extension] ...

Causes the listed file extensions to be ignored, even if they were previously defined to be part of a language.  The list is space-separated.  ex. “Ignore Extensions: cvs txt

Language: [name]
-Alter Language: [name]

Creates a new language or alters an existing one.  Names can use any characters.  Note the special behavior for languages named Shebang Script and Text File.

If you’re altering an existing language and a property has an [Add/Replace] form, you have to specify whether you’re adding to or replacing the list if that property has already been defined.

General Language Properties
Extensions: [extension] [extension] ...
-[Add/Replace] Extensions: [extension] [extension] ...

Defines file extensions for the language’s source files.  The list is space-separated.  ex. “Extensions: c cpp”.  You can use extensions that were previously used by another language to redefine them.  You can use * to specify all undefined extensions.

Shebang Strings: [string] [string] ...
-[Add/Replace] Shebang Strings: [string] [string] ...

Defines a list of strings that can appear in the shebang (#!) line to designate that it’s part of this language.  They can appear anywhere in the line, so php will work for “#!/user/bin/php4”.  You can use strings that were previously used by another language to redefine them.

Ignore Prefixes in Index: [prefix] [prefix] ...
-Ignore [type] Prefixes in Index: [prefix] [prefix] ...
-
-[Add/Replace] Ignored Prefixes in Index: [prefix] [prefix] ...
-[Add/Replace] Ignored [type] Prefixes in Index: [prefix] [prefix] ...

Specifies prefixes that should be ignored when sorting symbols for an index.  Can be specified in general or for a specific topic type.  The prefixes will still appear, the symbols will just be sorted as if they’re not there.  For example, specifying ADO_ for functions will mean that ADO_DoSomething will appear under D instead of A.

Basic Language Support Properties

These attributes are only available for languages with basic language support.

Line Comments: [symbol] [symbol] ...

Defines a space-separated list of symbols that are used for line comments, if any.  ex. “Line Comment: //”.

Block Comments: [opening symbol] [closing symbol] [o.s.] [c.s.] ...

Defines a space-separated list of symbol pairs that are used for block comments, if any.  ex. “Block Comment: /* */”.

Enum Values: [global|under type|under parent]

Defines the behavior of enum values.  The default is global.

GlobalEnum values are always global and will be referenced as “Value”.
Under TypeEnum values appear under the type and will be referenced as “Package.Enum.Value”.
Under ParentEnum values appear under the parent and will be referenced as “Package.Value”
[type] Prototype Enders: [symbol] [symbol] ...

When defined, Natural Docs will attempt to collect prototypes from the code following the specified topic type.  It grabs code until the first ender symbol or the next Natural Docs comment, and if it contains the topic name, it serves as its prototype.  Use \n to specify a line break.  ex. “Function Prototype Enders: { ;”, “Variable Prototype Enders: = ;”.

Line Extender: [symbol]

Defines the symbol that allows a prototype to span multiple lines if normally a line break would end it.

Perl Package: [perl package]

Specifies the Perl package used to fine-tune the language behavior in ways too complex to do in this file.

Full Language Support Properties

These attributes are only available for languages with full language support.

Full Language Support: [perl package]

Specifies the Perl package that has the parsing routines necessary for full language support.

Copyright © 2003-2010 Greg Valure
\ No newline at end of file diff --git a/vendor/naturaldocs/Help/customizingtopics.html b/vendor/naturaldocs/Help/customizingtopics.html deleted file mode 100644 index 92a17f293..000000000 --- a/vendor/naturaldocs/Help/customizingtopics.html +++ /dev/null @@ -1,74 +0,0 @@ - - -Customizing Natural Docs Topics - - - -
Natural Docs
Customizing Topics
Topics.txt

Natural Docs has two files called Topics.txt: one in its Config directory, and one in your project directory.  These control the topic behavior and keywords Natural Docs uses.

You should edit the one in your project directory whenever possible.  It keeps your changes separate and easier to manage, plus you don’t have to reapply them whenever you upgrade.  Editing the one in Natural Docs’ Config directory would be better only if you’re using Natural Docs with a lot of projects and would like the changes to apply everywhere.

Topic Types vs. Keywords

It’s important to understand the difference between topic types and keywords.  Topic types have their own indexes and behavior settings.  You’ll reference them by name when dealing with indexes in the menu file or prototype detection in the language file, but not when documenting your code unless you make their names keywords as well.

You use keywords when documenting your code.  There can be many keywords per topic type, and they are completely interchangable.

Suppose you document a class with the Class keyword and a struct with Struct.  They are both keywords for the Class topic type by default, so they will appear in the same index.  If you wanted structs to have their own index, you would add a topic type for structs and change the Struct keyword to point to it.

Adding Topic Types

If you want to be able to document something in Natural Docs doesn’t handle by default, you want to create your own topic type for it.  Let’s say you’re working on a video game and you want to document all the sound effects because you want to keep track of what each one is for and have an index of them.  You’d add this to your topics file:

Topic Type: Sound Effect
-   Plural: Sound Effects
-   Keywords:
-      sound
-      sound effect
-

Sound effects can now be documented with the sound or sound effect keywords, and they’ll get their own index.  The Plural line just specifies the plural name of the topic type.  It isn’t required, but Natural Docs will use it in some places where the plural would sound more natural, like when grouping topics or naming indexes on the menu.

Here are a couple of other things you may want to add:

Topic Type: Sound Effect
-   Plural: Sound Effects
-   Scope: Always Global
-   Keywords:
-      sound, sounds
-      sound effect, sound effects
-

You can set the scope behavior of the topic type.  Your options are:

NormalTopics stay within the current scope.
StartTopics start a new scope for all the topics beneath it, like class topics.
EndTopics reset the scope back to global for all the topics beneath it.
Always GlobalTopics are defined as global, but do not change the scope for any other topics.

Here we set it to Always Global so that if we document one as part of a class, it will still be global yet will not break the class’ scope.  In other words, we can always link to it with just its name instead of needing something like <Class.Sound>.

The other thing we did was add plural keywords, which you do by using a comma after an existing keyword.  These keywords are used for list topics so we don’t have to document each one individually with the full syntax.

There are more options, these are just the most important ones.  See the full syntax reference for the rest.

Prototypes

If you’d like to collect prototypes for your new topic type, you have to do that by editing Languages.txt.

Changing Keywords
Adding and Changing

If you’re defining your own topic type or editing the main topics file, you simply add to the keywords list:

Topic Type: Sound Effect
-   Keywords:
-      sound, sounds
-      sound effect, sound effects
-

It doesn’t matter if the keyword was previously defined for a different topic type.  Just define it again and the definition will change.

If you want to add keywords to one of the main topic types from the project file, use Alter Topic Type instead:

Alter Topic Type: General
-   Keywords:
-      note
-      notes
-

Natural Docs will keep a list of the main file’s topic types in your project file so that you can do this easily.

Ignoring

Sometimes a keyword just gets in the way.  It’s too common in your comments and Natural Docs keeps accidentally picking them up as topics when that isn’t what you wanted.  You can get rid of keywords completely by either deleting them from the main file or putting this in your project file:

Ignore Keywords:
-   about
-   title
-

If you only have a few, you can use this syntax as well:

Ignore Keywords: note, notes, title
-
Altering Behavior

You can change the behavior of any topic type defined in the main file via your project file.  Just use Alter Topic Type and redefine any property.

Alter Topic Type: Constant
-   Scope: Always Global
-

Natural Docs will keep a list of the main file’s topic types in your project file so you can do this easily.  See the syntax reference below for a full list of your options.

Syntax Reference
Ignore Keywords: [keyword], [keyword] ...
-   [keyword]
-   [keyword], [keyword]
-   ...
-

Ignores the keywords so that they’re not recognized as Natural Docs topics anymore.  Can be specified as a list on the same line and/or following like a normal Keywords section.

Topic Type: [name]
-Alter Topic Type: [name]
-

Creates a new topic type or alters an existing one.  The name can only contain letters, numbers, spaces, and these characters: . - ‘ /.  It isn’t case sensitive, although the original case is remembered for presentation.

There are a number of default types that must be defined in the main file, but they will be listed there since it may change between versions.  The default types can have their keywords or behaviors changed, though, either by editing the default file or by overriding them in the user file.

Properties
Plural: [name]
-

Specifies the plural name of the topic type.  Defaults to the singular name.  Has the same restrictions as the topic type name.

Index: [yes|no]
-

Whether the topic type gets an index.  Defaults to yes.

Scope: [normal|start|end|always global]
-

How the topic affects scope.  Defaults to normal.

NormalTopics stay within the current scope.
StartTopics start a new scope for all the topics beneath it, like class topics.
EndTopics reset the scope back to global for all the topics beneath it.
Always GlobalTopics are defined as global, but do not change the scope for any other topics.
Class Hierarchy: [yes|no]
-

Whether the topic is part of the class hierarchy.  Defaults to no.

Page Title if First: [yes|no]
-

Whether the title of this topic becomes the page title if it is the first topic in a file.  Defaults to no.

Break Lists: [yes|no]
-

Whether list topics should be broken into individual topics in the output.  Defaults to no.

Can Group With: [topic type], [topic type], ...
-

Lists the topic types that can be grouped with this one in the output.  If two or more topic types often appear together, like Functions and Properties, this will allow them to be grouped together under one heading if it would cause too many groups otherwise.

Keywords:
-   [keyword]
-   [keyword], [plural keyword]
-   ...
-

A list of the topic type’s keywords.  Each line after the heading is the keyword and optionally its plural form.  This continues until the next line in “keyword: value” format.

  • Keywords can only have letters, numbers, and spaces.  No punctuation or symbols are allowed.
  • Keywords are not case sensitive.
  • Subsequent keyword sections add to the list.  They don’t replace it.
  • Keywords can be redefined by appearing in later keyword sections.
Copyright © 2003-2010 Greg Valure
\ No newline at end of file diff --git a/vendor/naturaldocs/Help/documenting.html b/vendor/naturaldocs/Help/documenting.html deleted file mode 100644 index 465ca9538..000000000 --- a/vendor/naturaldocs/Help/documenting.html +++ /dev/null @@ -1,58 +0,0 @@ - - -Documenting Your Code - Natural Docs - - - -
Natural Docs
Using
Documenting
Your Code
KeywordsRunningTroubleshooting
Documenting Your Code

Here’s a quick example of how to document your code for Natural Docs.  If you’re a new user, we have a walkthrough to get you started.  Otherwise, visit the reference for the full details.

/*
-   Function: Multiply
-
-   Multiplies two integers.
-
-   Parameters:
-
-      x - The first integer.
-      y - The second integer.
-
-   Returns:
-
-      The two integers multiplied together.
-
-   See Also:
-
-      <Divide>
-*/
-int Multiply (int x, int y)
-   {  return x * y;  };
Copyright © 2003-2010 Greg Valure
\ No newline at end of file diff --git a/vendor/naturaldocs/Help/documenting/reference.html b/vendor/naturaldocs/Help/documenting/reference.html deleted file mode 100644 index 3a6b5f34d..000000000 --- a/vendor/naturaldocs/Help/documenting/reference.html +++ /dev/null @@ -1,147 +0,0 @@ - - -Documenting Your Code: Reference - Natural Docs - - - -
Natural Docs
Documenting Your Code
int Add (int x,
int y)
Adds two integers.
int Subtract (int x,
int y)
Subtracts two integers.
int Multiply (int x,
int y)
Multiplies two integers.
int Divide (int x,
int y)
Divides two integers.
bool IsEqual (int x,
int y)
Returns whether two integers are equal.
Comments

There is no special comment style for Natural Docs.  You just embed Natural Docs topics into regular comments, and it’s pretty tolerant as far as style goes.  You can use block comments or string together line comments.  The only requirement is that the comments are not on the same line as code.

/* Function: Multiply
-   Multiplies two integers and returns the result. */
-
-// Function: Multiply
-// Multiplies two integers and returns the result.
-

Note that when stringing line comments together, blank lines that you want to include in the documentation must start with the comment symbol as well.  If a line is completely blank, it’s considered the end of the comment and thus the end of the Natural Docs topic.

Boxes and Horizontal Lines

Natural Docs can also handle comment boxes and horizontal lines.  It doesn’t matter what symbols they use.  The boxes don’t need to be closed on the right side, and they can have different symbols for the edges and corners.

/*
- * Function: Multiply
- * Multiplies two integers and returns the result.
- */
-
-/* +-------------------------------------------------+
-   | Function: Multiply                              |
-   | Multiplies two integers and returns the result. |
-   +-------------------------------------------------+ */
-
-//////////////////////////////////////////////////////////////
-//
-//  Function: Multiply
-//  ------------------
-//
-//  Multiplies two integers together and returns the result.
-//
-//////////////////////////////////////////////////////////////
-
Javadoc Style

If you have full language support, you can also use Javadoc-style comments to write Natural Docs documentation.  To do this you repeat the last symbol on the first line of the comment once.  The comment must appear directly above what it’s documenting, and you can omit the topic line if you want (the “Function: Multiply” part.)

/**
- * Multiplies two integers and returns the result.
- */
-
-///
-// Multiplies two integers together and returns the result.
-

If you omit the topic line and include any Javadoc tags in the comment, like @param, the entire comment will be treated as Javadoc and can only use Javadoc formatting.  Otherwise it’s treated as a Natural Docs comment and you can use all the formatting options described on this page.  You can have both styles in the same source file, but not in the same comment.

Perl POD

Perl users can also use POD to do block comments.

=begin nd
-
-Function: Multiply
-Multiplies two integers and returns the result.
-
-=cut
-

You can also use NaturalDocs or Natural Docs in place of ND.  None of them are case sensitive.  If for some reason you want to go back to POD documentation instead of using =cut, you can write =end nd.

There’s a second form of just =nd which is offered as a convenience.  However, it is not valid POD.  Perl will skip over it and execute fine, but POD parsers will give errors and possibly include the unformatted text in the output.  Use the longer, valid form unless you know for certain that no one will ever try to run POD on your code.

=nd
-
-Function: Multiply
-Multiplies two integers and returns the result.
-
-=cut
-
Text Files

Documentation can also be included in text files.  Any file with a .txt extension appearing in the source tree and starting with a topic line will included in the documentation.  It will be treated the same as a source file, meaning it will appear in the menu, its topics will be in the indexes, and its topics can be linked to from anywhere in the documentation.  The only difference is you don’t need comment symbols.

Remember that the topic line is required to be the first line of content.  If the first non-blank line is not in the “Function: Multiply” format the file will be ignored.  An easy way to do this is to use the Title keyword, although all of the other ones will work as well.

Title: License
-
-This project is licensed under the GPL.
-

This method is convenient for documenting file formats, configuration settings, the general program architecture, or anything else that isn’t directly tied to a source file.

Keywords, Topics, and Scope

A topic in Natural Docs starts with a topic line in the format “keyword: name”.  You can have multiple topics per comment as long as you separate them with a blank line.  The keywords aren’t case sensitive.

The list of keywords is pretty predictable: Function, Class, Variable, etc.  Just use what you’re documenting.  There are many synonyms as well, so you can use keywords like Func, Procedure, Proc, Method and Constructor.  Look at the full list of keywords to see everything that’s available.

The list of keywords is separated into topic types.  Each type gets its own index, and which specific keyword you use doesn’t matter.  Some also have scoping rules or other behavior as noted.

Scope

Like the code it’s documenting, Natural Docs topics have scope.  This mostly has to do with linking: if you’re in a class you can link to its members by their name alone, but if you’re not, you have to use a notation like class.member or class::member.

If you have full language support and are documenting something that appears in the code, the scope will be handled automatically.  If you’re using text files, have basic language support, or are including a topic that doesn’t correspond to something in the code, scoping follows these rules:

List Topics

If you looked at the list, you saw that most of the keywords have plural forms.  That’s for list topics, which let you document many small things without using the full syntax.  Anything that appears in definition lists within that topic will be treated as if it had its own topic.  It will appear in the indexes and be linkable, just like normal topics.

Function list topics will automatically break apart in the output as well, so it will look the same as if you documented each one individually.

Linking

Linking is the one place where Natural Docs has some negative effect on the readability of the comments.  The alternative would be to automatically guess where links should be, but systems that do that can sometimes pepper your sentences with unintentional links to functions called “is” or “on”.  However, the Natural Docs syntax is still as minimal as possible.  Simply surround any topic you want to link to with angle brackets.  Natural Docs will keep track off all the topics and where they are defined, so you don’t need to use HTML-like syntax or remember what file anything is in.  Also, if the link can’t be resolved to anything, Natural Docs leaves the angle brackets in the output so if something wasn’t intended to be a link (such as #include <somefile.h>) it won’t be mangled.

Let's link to function <Multiply>.
-

Let’s link to function Multiply.

Links and topic names are case sensitive, regardless of whether the language is or not.

When linking to functions, it doesn’t matter if you include empty parenthesis or not.  Both <Function> and <Function()> will work.  However, if you documented the function with parameters as part of the name, you will need to include those parameters whenever linking to it.  It is recommended that you only include parameters in the topic name if you need to distinguish between two functions with the same name.

If the topic has a summary sentence, hovering over the link will give it to you as a tooltip.  If the topic has a prototype, that will be included as well.  You can try it above.

Scope

If a topic is considered part of a class, they can be linked to using any of the three most common class/member notations:  class.member, class::member, and class->member.  Natural Docs will not be confused by <class->member>.  Like in the language itself, if the topic you’re writing is in that class’ scope you can link to it simply as <member>.

If you have multi-level classes and packages, links can be relative as well.  So if you’re in Project::UI::Window::Base and you want to link to Project::UI::Button::Base, just using <Button::Base> will work.

Plurals and Possessives

To make the documentation easier to write and easier to read in the source file, you can include plurals and possessives inside the angle brackets.  In other words, you don’t have to use awkward syntax like <Object>s, although that’s supported as well.  You can simply write <Objects> and it will link to the symbol Object just fine.  It can handle any plural and/or possessive form you can throw at it.  I’m not kidding: Foxes, Fox’s, Foxes’, Children, Mice, Alumni, Indices, Amoebae, Teeth, just try to trip it up.

URLs and E-Mail

You can also link to URLs and e-mail addresses.  It will detect them automatically, but you can also put them in angle brackets if you like.

Visit <http://www.website.com> or send messages to
-email@address.com.
-

E-mail addresses are protected in a way that should avoid spam crawlers.  Although the link above looks and acts like a regular link (try it) the HTML code actually looks like this:

<a href="#"
- onClick="location.href='mai' + 'lto:' + 'em' + 'ail' + '@'
-          + 'addre' + 'ss.com'; return false;">
-    em<span style="display: none">.nosp@m.</span>ail
-    <span>@</span>
-    addre<span style="display: none">.nosp@m.</span>ss.com
-</a>
-

You can create named links by putting the text, “at”, and then the address in the angle brackets.  This format lets it read naturally in a sentence.

Visit <the website at http://www.website.com> or <e-mail me at email@address.com>.
-
Formatting and Layout

You can apply additional formatting and layout to your Natural Docs content, all in ways that will appear very natural in the source code.

Paragraphs

You can break paragraphs by leaving blank lines between them.  So we have this in our content:

The first paragraph blah blah blah blah blah blah blah blah
-blah blah blah blah blah blah blah blah blah blah blah blah
-blah blah blah blah.
-
-The second paragraph blah blah blah blah blah blah blah
-blah blah blah blah blah blah blah blah blah blah blah blah
-blah blah blah blah.
-

and we get this in our output:

The first paragraph blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah.

The second paragraph blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah.

Bold and Underline

You can apply bold to a stretch of text by surrounding it with asterisks.  You can apply underlining by surrounding it with underscores instead.  With underlining, it doesn’t matter if you use an underscore for every space between words or not; they’ll be converted to spaces if you do.

Some *bold text* and some _underlined text_
-and yet _more_underlined_text_.
-

Some bold text and some underlined text and yet more underlined text.

Headings

You can add headings to your output just by ending a line with a colon and having a blank line above it.

Some text before the heading.
-
-Heading:
-Some text under the heading.
-

Some text before the heading.

Heading

Some text under the heading.

You must have a blank line above the heading or it will not work.  You can skip the blank after it but not before.

Bullet Lists

You can add bullet lists by starting a line with a dash, an asterisk, an o, or a plus.  Bullets can have blank lines between them if you want, and subsequent lines don’t have to be indented.  You end a list by skipping a line and doing something else.

- Bullet one.
-- Bullet two.
-  Bullet two continued.
-- Bullet three.
-
-Some text after the bullet list.
-
-o Spaced bullet one.
-
-o Spaced bullet two.
-Spaced bullet two continued.
-
-o Spaced bullet three.
-
-Some text after the spaced bullet list.
-
  • Bullet one.
  • Bullet two.  Bullet two continued.
  • Bullet three.

Some text after the bullet list.

  • Spaced bullet one.
  • Spaced bullet two.  Spaced bullet two continued.
  • Spaced bullet three.

Some text after the spaced bullet list.

Definition Lists

You can add a definition list by using the format below, specifically “text space dash space text”.  Like bullet lists, you can have blank lines between them if you want, subsequent lines don’t have to be indented, and you end the list by skipping a line and doing something else.

First  - This is the first item.
-Second - This is the second item.
-         This is more of the second item.
-Third  - This is the third item.
-This is more of the third item.
-
-Some text after the definition list.
-
FirstThis is the first item.
SecondThis is the second item.  This is more of the second item.
ThirdThis is the third item.  This is more of the third item.

Some text after the definition list.

Remember that with definition lists, if you’re using the plural form of the keywords each entry can be linked to as if it had its own topic.

Code and Text Diagrams

You can add example code or text diagrams by starting each line with >, |, or :.  If you have a vertical line or text box with the comment, you must separate these symbols from it with a space.

: a = b + c;
-
->   +-----+     +-----+
->   |  A  | --> |  B  |
->   +-----+     +-----+
->                  |
->               +-----+
->               |  C  |
->               +-----+
-
a = b + c;
+-----+     +-----+
| A | --> | B |
+-----+ +-----+
|
+-----+
| C |
+-----+

For long stretches, this may be too tedious.  You can start a code section by placing (start code) or just (code) alone on a line.  You end it with either (end code) or just (end).  You can’t put any other content on these lines.

(start code)
-
-if (x == 0) {
-   DoSomething();
-}
-
-return x;
-
-(end)
-
if (x == 0) {
DoSomething();
}

return x;

You can also use example, diagram, or table instead of code.  Just use whatever’s appropriate.  Always flexible, it will accept begin for start and it will accept finish or done for end so you don’t have to remember the exact word.

Syntax highlighting will be applied to (start code) sections by default.  If you’d like to also apply it to >, :, and | lines or turn it off completely, use the -hl command line option.

Images

You can include images in your documentation by writing “(see filename)”.  If you put it alone on a line it will be embedded in place.

This is the first paragraph.
-
-(see logo.gif)
-
-This is the second paragraph.
-

This is the first paragraph.

This is the second paragraph.

If it’s not alone on a line the image will appear after the end of the paragraph, the text will become a link to it, and the file name will be used as a caption.

This is the first paragraph (see logo.gif)  This is
-more of the first paragraph.
-

This is the first paragraph (see logo)  This is more of the first paragraph.

logo

The image file names are relative to the source file the comment appears in or any directories specified with the -img command line option.  You can use relative paths like (see images/logo.gif) and (see ../images/logo.gif), but you cannot use absolute paths, URLs, or specify a file that’s not in a folder included by -i or -img.

Natural Docs supports gif, jpg, jpeg, png, and bmp files.

Page Titles

Natural Docs automatically determines the page title as follows:

  • If there’s only one topic in the file, that topic’s title becomes the page title.
  • Otherwise, if the first topic in the file is a class, section, or file, that topic’s title becomes the page title.
  • Otherwise, the file name becomes the page title.

This should be enough for most people.  However, if you don’t like the page title Natural Docs has chosen for you, add a “Title: [name]” comment to the top of the file to override it.  Title is a synonym of Section, so that will satisfy the second rule and make it the page title.

Summaries

Summaries are automatically generated for every file, class, and section.  You don’t have to do anything special to get them.

There are two things you may want to keep in mind when documenting your code so that the summaries are nicer.  The first is that they use the first sentence in the topic as the description, so long as it’s plain text and not something like a bullet list.  It will also appear in the tooltip whenever that topic is linked to.

The second is that you may want to manually add group topics to divide long lists and make the summaries easier to navigate.  Natural Docs will automatically group them by type if you do not, but sometimes you want to be more specific.  You don’t need to provide a description, just adding a “Group: [name]” comment is sufficient.  Note that once you manually add a group automatic grouping is completely turned off for that class.

Here’s an example summary.  Note that as before, when you hover over a link, you’ll get the prototype and summary line as a tooltip.

Summary
A example class that does arithmetic with functions for people scared of operators.
Adds two integers.
Subtracts two integers.
Multiplies two integers.
Divides two integers.
Returns whether two integers are equal.
Javadoc Compatibility

If you have full language support Natural Docs will also extract documentation from actual Javadoc comments, not just Natural Docs comments written with the Javadoc comment symbols.  This provides you with a good method of migrating to Natural Docs as you don’t have to convert all of your existing documentation.

/**
- * Multiplies two integers.
- *
- * @param x The first integer.
- * @param y The second integer.
- * @return The two integers multiplied together.
- * @see Divide
- */
-

Multiply

int Multiply (int x,
int y)

Multiplies two integers.

Parameters

xThe first integer.
yThe second integer.

Returns

The two integers multiplied together.

See Also

Divide

While most Javadoc tags and simple HTML formatting are supported, Natural Docs is not a full Javadoc parser and may not support some advanced tags and HTML.  See this page for a list of what’s supported and what isn’t.

A source file can contain both Natural Docs and Javadoc comments.  However, you cannot mix the two within a single comment.  For example, you can’t use asterisks for bold in a @param line.  If a comment is written with the Javadoc comment symbols (repeat the last symbol of the first line once) doesn’t have a topic line (like “Function: Multiply”) and uses Javadoc tags (like @param) the comment is treated as Javadoc.  If any of those conditions aren’t true it’s treated as a Natural Docs comment.

Copyright © 2003-2010 Greg Valure
\ No newline at end of file diff --git a/vendor/naturaldocs/Help/documenting/walkthrough.html b/vendor/naturaldocs/Help/documenting/walkthrough.html deleted file mode 100644 index 055d0b82a..000000000 --- a/vendor/naturaldocs/Help/documenting/walkthrough.html +++ /dev/null @@ -1,181 +0,0 @@ - - -Documenting Your Code - Walkthrough - Natural Docs - - - -
Natural Docs
Documenting Your Code
Our First Function

So you downloaded Natural Docs, you figured out the command line, and now it’s time to start documenting your code.  Natural Docs tries to make this very straightforward and painless, so let’s just dive right in:

/*
-   Function: Multiply
-   Multiplies two integers and returns the result.
-*/
-int Multiply (int x, int y)
-   {  return x * y;  };
-

That’s all you need.  Run Natural Docs and here’s what appears in your output:

Multiply

int Multiply (int x,
int y)

Multiplies two integers and returns the result.

Okay, so that’s all you need, but probably not all you want.  After all, you’ve got some real functions to document, not little one-liners.  Here’s something more elaborate:

/*
-   Function: Multiply
-
-   Multiplies two integers.
-
-   Parameters:
-
-      x - The first integer.
-      y - The second integer.
-
-   Returns:
-
-      The two integers multiplied together.
-
-   See Also:
-
-      <Divide>
-*/
-int Multiply (int x, int y)
-   {  return x * y;  };
-

Multiply

int Multiply (int x,
int y)

Multiplies two integers.

Parameters

xThe first integer.
yThe second integer.

Returns

The two integers multiplied together.

See Also

Divide

int Add (int x,
int y)
Adds two integers.
int Subtract (int x,
int y)
Subtracts two integers.
int Multiply (int x,
int y)
Multiplies two integers.
int Divide (int x,
int y)
Divides two integers.
bool IsEqual (int x,
int y)
Returns whether two integers are equal.

Still not too scary, huh?  Notice the comments are just as readable as the output.  No tags littered about, and the structure is very natural.  You probably get it just by looking at it, but let’s go through the details anyway.

Function: Multiply
-

Every one of these comments you write (called topics) are going to start with a topic line in the format “keyword: title”.  There are a lot of keywords, but they’re exactly what you’d expect: Function, Class, Variable, etc.  There are also a lot of synonyms so instead of Function you could use Func, Procedure, Proc, Method, Constructor, etc.  It’s designed so you can just use whatever it is you’re describing without memorizing anything.  You can glance over the keyword list but you shouldn’t have to consult it very often.

The other part of the topic line is the title.  It should match whatever it is you’re documenting, in this case the function name Multiply.  Natural Docs is case sensitive even if your programming language isn’t, so make sure you match it closely or you might not get the prototype in your output, which is the little gray box.  You don’t need to include the parameters in the title.  In fact, it’s better if you don’t.

Parameters:
-
-Returns:
-
-See Also:
-

You can also define headings by skipping a line and ending the text with a colon.  If you’re used to other documentation systems you may think there’s only a handful of headings to choose from, but any text formatted this way will become one.  If you want a heading called Dependencies you can go right ahead and add it.

x - The first integer.
-y - The second integer.
-

This is what’s called a definition list.  You can use more than one line to finish the definition, as it won’t stop until you skip a line.

x - The first integer.
-y - The second integer with a long description.
-    This is still part of the description.
-
-This is a new paragraph because we skipped a line.
-

Indentation doesn’t matter either, so even if the second description line wasn’t indented to match the first, it would still be considered part of it.

<Divide>
-

This is how we link in Natural Docs, with angle brackets.  There will be a lot more to say about this later, but for now I’ll just show you something cool.  Hover over it in the output below:

You get that everywhere in your generated documentation.

Classes and Scope

So that’s good for our one function of questionable usefulness, but what if we have a whole class of questionable usefulness?  We can document the class and it’s members the same way we documented the individual function, with a Natural Docs comment right above each element.  We’ll go back to short descriptions to keep the example manageable.

/*
-   Class: Counter
-   A class that manages an incrementing counter.
-*/
-class Counter
-   {
-   public:
-
-      /*
-         Constructor: Counter
-         Initializes the object.
-      */
-      Counter()
-         {  value = 0;  };
-
-      /*
-         Function: Value
-         Returns the value of the counter.
-      */
-      int Value()
-         {  return value;  };
-
-      /*
-         Function: Increment
-         Adds one to the counter.
-      */
-      void Increment()
-         {  value++;  };
-
-   protected:
-
-      /*
-         Variable: value
-         The counter's value.
-      */
-      int value;
-   };
-

Everything’s the same, we just substituted Class and Variable for the Function keyword when it was appropriate.  We also used Constructor, but we could have just as easily used Function there too.  They’re both keywords for the same thing so it doesn’t matter.

Scope

Like the source code itself, Natural Docs topics have scope.  Value and Increment are seen as part of class Counter, just like they are in the code.  Why is this important?  Linking.  Linking from one topic to another has similar rules to how one function can call another.  Since Value is in the same class as Increment, it’s topic can link to it with just <Increment>.  However, linking to Increment from a different class would require <Counter.Increment> instead.  You can actually use any of the three most common class/member notations: <Counter.Increment>, <Counter::Increment>, and <Counter->Increment>.

If your programming language has full language support, the scope is determined by the code and applied automatically.  However, if you only have basic language support it follows these rules:

  • Any topic that appears under a Class topic (or anything that says Starts Scope) is part of that class.
  • Any topic that appears under a Section topic (or anything that says Ends Scope) is global again.
  • Any File topic (or anything that says Always Global) is global no matter what and doesn’t affect any other topics.

Chances are you would have written the same thing even if you didn’t know this and it would have just worked.  You usually won’t need to think about them at all.  However, it’s still good to be aware of them in case something doesn’t behave the way you expected it to.

You actually know enough to go start documenting now.  I know Mr. ScrollBar says there’s more on this page you can learn, but if you want to skip out early, you can.  Really.  I don’t mind.

More Formatting

Okay then.  On we go.

Paragraphs, Bold, and Underline

The syntax for these three is exactly what you would expect it to be.

*Bold text*
-
-_Underlined text_
-
-Paragraphs are broken by skipping lines.  So the two
-lines above each have their own paragraph, but these
-three lines are all part of the same one.
-

Bold text

Underlined text

Paragraphs are broken by skipping lines.  So the two lines above each have their own paragraph, but these three lines are all part of the same one.

When underlining multiple words, you can use an underscore for each space or only put them at the edges like we did above.  Both ways will work.

Bullet Lists

You can add bullet lists by starting a line with a dash, an asterisk, an o, or a plus.  Like definition lists, bullets can span multiple lines and indentation doesn’t matter.  To end a bullet you have to skip a line before doing something else.

- Bullet one.
-- Bullet two.
-  Bullet two continued.
-- Bullet three.
-
-Some text after the bullet list.
-
  • Bullet one.
  • Bullet two.  Bullet two continued.
  • Bullet three.

Some text after the bullet list.

Code and Text Diagrams

You can add example code or text diagrams by starting each line with >, |, or :.

> a = b + c;
-> b++;
-
a = b + c;
b++;

If you have a long stretch, you can use (start code) and (end) instead.

(start code)
-
-if (x == 0) {
-   DoSomething();
-}
-
-return x;
-
-(end)
-
if (x == 0) {
DoSomething();
}

return x;

You can also use example, diagram, or table instead of code.  Just use whatever’s appropriate.

As I mentioned before, we don’t want you to worry about memorizing minor details, so in that spirit it will also accept begin for start and finish or done for end.  You can also write (end code) instead of just (end).

Syntax highlighting will be applied to (start code) sections by default.  If you’d like to also apply it to >, :, and | lines or turn it off completely, use the -hl command line option.

Images

You can include images in your documentation by writing “(see filename)”.  If you put it alone on a line it will be embedded in place, or if you put it in a paragraph it will appear after it using the file name as a caption.

This is the first paragraph.
-
-(see logo.gif)
-
-This is the second paragraph (see logo.gif)  This
-is more of the second paragraph.
-

This is the first paragraph.

This is the second paragraph (see logo)  This is more of the second paragraph.

logo

The image file names are relative to the source file the comment appears in, so if your file is C:\Project\SourceFile.cpp and your image is C:\Project\Images\Logo.gif, you would write (see Images/Logo.gif).  However, you can also specify image directories in the command line with -img, so if all your source files are in C:\Project\Source and all your images are in C:\Project\Images, you can put “-img C:\Project\Images” on the command line and just use (see logo.gif) again.

More on Linking

Yes, there’s still more to linking.  You can link to URLs and e-mail addresses, but in this case the angle brackets are optional.

Visit <http://www.website.com> or send messages to
-email@address.com.
-

You can create named links by putting the text, “at”, and then the address in the angle brackets.  This format lets it read naturally in a sentence.

Visit <the website at http://www.website.com> or <e-mail me at email@address.com>.
-

E-mail addresses are protected from spam crawlers.  They look and act like regular links (try it above) but you can see the actual HTML that’s generated for them here.

As for regular links, to help them fit into sentences easily you can actually include plurals and possessives inside the angle brackets.  In other words, you don’t have to use awkward syntax like <Object>s, although that’s supported as well.  You can simply write <Objects> and it will link to the symbol Object just fine.  It can handle any plural and/or possessive form you can throw at it.  I’m not kidding: Foxes, Fox’s, Foxes’, Children, Mice, Alumni, Indices, Amoebae, Teeth, just try to trip it up.

Extra Documentation

Sometimes you want to include documentation that doesn’t correspond directly to a code element.  Maybe you want to include license information or architecture notes.  There are two ways to do this.

Freestanding Topics

Just because most of the things you write will directly correspond to an element of your source code doesn’t mean they have to.  You can pick any of the available keywords and create a freestanding comment with it.  For example:

/*
-   Class: Counter
-   A class that manages an incrementing counter.
-*/
-class Counter
-   {
-   public:
-
-      /*
-         About: License
-         This file is licensed under the GPL.
-      */
-
-      /*
-         Constructor: Counter
-         Initializes the object.
-      */
-      Counter()
-         {  value = 0;  };
-   ...
-

The extra license topic will be added to the output just like the functions.

License

This file is licensed under the GPL.

Remember that because of scope, the License topic will actually be considered part of Counter the way it’s listed above.  You’d link to it from outside Counter with <Counter.License>.  That idea may take some getting used to, but if an extra topic only applies to one class that’s actually the most appropriate way to do it.  In this case it’s a license, so if it applies to the entire project instead you could put the comment above the class to make it global, just like moving a function there would.

Text Files

You can also add additional documentation with text files.  If you put a file with a .txt extension in your source tree and start it with a topic line, it’s contents will be treated the same as if it were in a comment in your source code.  That means you can define multiple topics within it, you can link between them and topics in your source code, and you can use all available formatting options.

Title: License
-
-This file is licensed under the GPL.
-
-I can link to <Counter> and <Counter.Increment>, and
-the documentation in that class can even link back
-with <License>.
-
-
-About: Second Topic
-
-I can create a *second* topic in here too, complete
-with formatting.
-

The thing some people forget though is that you must start it with a topic line, like “Title: License” above.  This is how Natural Docs tells it apart from regular text files.

Abbreviated Syntax

Here’s another useful thing you may want to know about.  Suppose you have a lot of little things to document, like constants.  Writing a separate topic for each one can be very tedious, no matter how much you compress it:

// Constant: COUNTER_NORMAL
-// Causes the counter to increment normally.
-#define COUNTER_NORMAL 0
-
-// Constant: COUNTER_ODD
-// Causes the counter to only increment in odd numbers.
-#define COUNTER_ODD 1
-
-// Constant: COUNTER_EVEN
-// Causes the counter to only increment in even numbers.
-#define COUNTER_EVEN 2
-

One thing you may have noticed in the keyword list is that they almost all have plural forms.  These are used to create what are called list topics.  You define a topic using a plural keyword, and then anything appearing in a definition list within it creates a linkable symbol as if they each had their own topic.  For example:

/*
-   Constants: Counter Modes
-
-   COUNTER_NORMAL - Causes the counter to increment normally.
-   COUNTER_ODD    - Causes the counter to only increment in odd numbers.
-   COUNTER_EVEN   - Causes the counter to only increment in even numbers.
-*/
-#define COUNTER_NORMAL 0
-#define COUNTER_ODD 1
-#define COUNTER_EVEN 2
-

I would now be able to write <COUNTER_ODD> and have it work the same as it would with the first example.

Using the enum or enumeration keyword is special because it automatically behaves in a similar manner.  This allows both the enum and its values to be documented in the same place.

/*
-   Enum: CounterMode
-
-   NORMAL - Causes the counter to increment normally.
-   ODD    - Causes the counter to only increment in odd numbers.
-   EVEN   - Causes the counter to only increment in even numbers.
-*/
-enum CounterMode { NORMAL, ODD, EVEN };
-

That’s it, you’re done with this walkthrough.  You should know enough now to make very good use of Natural Docs.  If you still want to know more, you can look in the reference for some of the smaller details we may have skipped over.  Also, look at the Customizing pages on this web site for even more you can do.

Copyright © 2003-2010 Greg Valure
\ No newline at end of file diff --git a/vendor/naturaldocs/Help/example/Default.css b/vendor/naturaldocs/Help/example/Default.css deleted file mode 100644 index 7318fdcd9..000000000 --- a/vendor/naturaldocs/Help/example/Default.css +++ /dev/null @@ -1,528 +0,0 @@ -/* - IMPORTANT: If you're editing this file in the output directory of one of - your projects, your changes will be overwritten the next time you run - Natural Docs. Instead, copy this file to your project directory, make your - changes, and you can use it with -s. Even better would be to make a CSS - file in your project directory with only your changes, which you can then - use with -s [original style] [your changes]. - - On the other hand, if you're editing this file in the Natural Docs styles - directory, the changes will automatically be applied to all your projects - that use this style the next time Natural Docs is run on them. - - This file is part of Natural Docs, which is Copyright © 2003-2004 Greg Valure - Natural Docs is licensed under the GPL -*/ - -body { - font-family: Verdana, Arial, sans-serif; - color: #000000; - margin: 0px; padding: 0px } - -body.UnframedPage { - background-color: #E8E8E8 } - - -a:link, -a:visited { color: #900000; text-decoration: none } -a:hover { color: #900000; text-decoration: underline } -a:active { color: #FF0000; text-decoration: underline } - -td { - vertical-align: top } - -/* - Comment out this line to use web-style paragraphs (blank line between - paragraphs, no indent) instead of print-style paragraphs (no blank line, - indented.) -*/ -p { - text-indent: 5ex; margin: 0 } - - -/* Can't use something like display: none or it won't break. */ -.HB { - font-size: 1px } - - - - -body.FramedMenuPage, -.MenuSection { - font-size: 9pt; - background-color: #E8E8E8; - padding: 10px 0 0 0 } - -.MenuSection { - width: 27ex } - - - .MTitle { - font-size: 16pt; font-weight: bold; font-variant: small-caps; - text-align: center; - padding: 5px 10px 15px 10px; - border-bottom: 1px dotted #000000; - margin-bottom: 15px } - - .MSubTitle { - font-size: 9pt; font-weight: normal; font-variant: normal; - margin-top: 1ex; margin-bottom: 5px } - - - .MEntry a:link, - .MEntry a:hover, - .MEntry a:visited { color: #606060; margin-right: 0 } - .MEntry a:active { color: #A00000; margin-right: 0 } - - - .MGroup { - font-variant: small-caps; font-weight: bold; - margin: 1em 0 1em 10px } - - /* Konqueror just can't do margins. */ - .KHTML .MGroup { - margin-bottom: 0; padding-bottom: 1em } - - .MGroupContent { - font-variant: normal; font-weight: normal } - - .MGroup a:link, - .MGroup a:hover, - .MGroup a:visited { color: #545454; margin-right: 10px } - .MGroup a:active { color: #A00000; margin-right: 10px } - - - .MFile, - .MText, - .MLink, - .MIndex { - padding: 1px 17px 2px 10px; - margin: .25em 0 .25em 0 } - - .MText { - font-size: 8pt; font-style: italic } - - .MLink { - font-style: italic } - - #MSelected { - color: #000000; background-color: #FFFFFF; - /* Replace padding with border. */ - padding: 0 10px 0 10px; - border-width: 1px 2px 2px 0; border-style: solid; border-color: #000000; - margin-right: 5px } - - /* Close off the left side when its in a group. */ - .MGroup #MSelected { - padding-left: 9px; border-left-width: 1px } - - /* A treat for Mozilla users. Blatantly non-standard. Will be replaced with CSS 3 attributes when finalized/supported. */ - .Gecko #MSelected { - -moz-border-radius-topright: 10px; - -moz-border-radius-bottomright: 10px } - .Gecko .MGroup #MSelected { - -moz-border-radius-topleft: 10px; - -moz-border-radius-bottomleft: 10px } - - - - -body.FramedContentPage, -.ContentSection { - background-color: #FFFFFF; - padding-bottom: 15px } - -.ContentSection { - border-width: 0 0 1px 1px; border-style: solid; border-color: #000000 } - - - .CTopic { - font-size: 10pt; - /* This should be a margin but Konq 3.1.1 sucks. */ - padding-bottom: 3em } - - - .CTitle { - font-size: 12pt; font-weight: bold; - border-width: 0 0 1px 0; border-style: solid; border-color: #A0A0A0; - margin: 0 15px .5em 15px } - - .CGroup .CTitle { - font-size: 16pt; font-variant: small-caps; - padding-left: 15px; padding-right: 15px; - border-width: 0 0 2px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - .CClass .CTitle, - .CInterface .CTitle, - .CDatabase .CTitle, - .CDatabaseTable .CTitle, - .CSection .CTitle { - font-size: 18pt; - color: #FFFFFF; background-color: #A0A0A0; - padding: 10px 15px 10px 15px; - border-width: 2px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - #MainTopic .CTitle { - font-size: 20pt; - color: #FFFFFF; background-color: #7070C0; - padding: 10px 15px 10px 15px; - border-width: 0 0 3px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - .CBody { - margin-left: 15px; margin-right: 15px } - - - .CToolTip { - position: absolute; visibility: hidden; - left: 0; top: 0; max-width: 50%; - background-color: #FFFFE0; - padding: 5px; - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #000000; - font-size: 8pt } - - /* Opera 6 gives it a huge height otherwise. */ - .Opera6 .CTooltip, .Opera5 .CTooltip { - max-width: 100% } - - .CHeading { - font-weight: bold; font-size: 10pt; - margin-top: 1.5em; margin-bottom: .5em } - - .CCode { - font: 10pt "Courier New", Courier, monospace; - overflow: auto; - } - - .CBulletList { - /* I don't know why CBody's margin doesn't apply, but it's consistent across browsers so whatever. - Reapply it here as padding. */ - padding-left: 15px; padding-right: 15px; - margin: .5em 5ex .5em 5ex; - } - - .CDescriptionList { - margin: .5em 5ex 0 5ex } - - /* IE 4 and Konqueror always makes it too long. */ - .IE4 .CDescriptionList, - .KHTML .CDescriptionList { - width: 85% } - - .CDLEntry { - font: 10pt "Courier New", Courier, monospace; color: #808080; - padding-bottom: .25em; - white-space: nowrap } - - .CDLDescription { - font-size: 10pt; /* For browsers that don't inherit correctly, like Opera 5. */ - padding-bottom: .5em; padding-left: 5ex } - - .CTopic img { - text-align: center; - display: block; - margin: 1em auto; - } - .CImageCaption { - font-variant: small-caps; - font-size: 8pt; - color: #808080; - text-align: center; - position: relative; - top: 1em; - } - - .CImageLink { - color: #808080; - font-style: italic; - } - a.CImageLink:link, - a.CImageLink:visited, - a.CImageLink:hover { color: #808080 } - - - -.Prototype { - font: 10pt "Courier New", Courier, monospace; - padding: 5px 3ex; - border-width: 1px; border-style: solid; - margin: 0 5ex 1.5em 5ex; - } - - .Prototype td { - font-size: 10pt; - } - - .PDefaultValue, - .PTypePrefix { - color: #8F8F8F; - } - .PTypePrefix { - text-align: right; - } - - .IE .Prototype table { - padding: 0; - } - - .CFunction .Prototype { - background-color: #F4F4F4; border-color: #D0D0D0 } - .CProperty .Prototype { - background-color: #F4F4FF; border-color: #C0C0E8 } - .CVariable .Prototype { - background-color: #FFFFF0; border-color: #E0E0A0 } - - .CDatabaseIndex .Prototype, - .CConstant .Prototype { - background-color: #D0D0D0; border-color: #000000 } - .CType .Prototype { - background-color: #FFF8F8; border-color: #E8C8C8 } - .CDatabaseTrigger .Prototype, - .CEvent .Prototype, - .CDelegate .Prototype { - background-color: #F0FCF0; border-color: #B8E4B8 } - - .CToolTip .Prototype { - margin: 0 0 .5em 0; - white-space: nowrap; - } - - - - - -.Summary { - margin: 1.5em 5ex 0 5ex } - - .STitle { - font-size: 12pt; font-weight: bold; - margin-bottom: .5em } - - - .SBorder { - background-color: #FFFFF0; - padding: 15px; - border: 1px solid #C0C060 } - - /* Let's observe the evolution of IE's brokeness, shall we? - IE 4 always makes them too long, there's no way around it. */ - .IE4 .SBorder { - width: 85% } - /* IE 5 will make them too long unless you set the width to 100%. Isn't this implied for a div? */ - .IE5 .SBorder { - width: 100% } - /* IE 6 behaves like 5 when it's in a frame, but without frames it will be correct without a width or slightly too long - (but not enough to scroll) with a width. This arbitrary weirdness simply astounds me. */ - body.FramedContentPage .IE6 .SBorder { - width: 100% } - - /* A treat for Mozilla users. Blatantly non-standard. Will be replaced with CSS 3 attributes when finalized/supported. */ - .Gecko .SBorder { - -moz-border-radius: 20px } - - - .STable { - font-size: 9pt; width: 100% } - - .SEntrySize { - width: 30% } - .SDescriptionSize { - width: 70% } - - - .SMarked { - background-color: #F8F8D8 } - - - .SEntry .SIndent1 { - margin-left: 1.5ex } - .SEntry .SIndent2 { - margin-left: 3ex } - .SEntry .SIndent3 { - margin-left: 4.5ex } - .SEntry .SIndent4 { - margin-left: 6ex } - .SEntry .SIndent5 { - margin-left: 7.5ex } - - .SDescription { - padding-left: 3ex } - - .SDescription a { color: #800000} - .SDescription a:active { color: #A00000 } - - - .SGroup { - margin-top: .5em; margin-bottom: .25em } - - .SGroup .SEntry { - font-weight: bold; font-variant: small-caps } - - .SGroup .SEntry a { color: #800000 } - .SGroup .SEntry a:active { color: #F00000 } - - - .SMain .SEntry, - .SClass .SEntry, - .SDatabase .SEntry, - .SDatabaseTable .SEntry, - .SSection .SEntry { - font-weight: bold; font-size: 10pt; - margin-bottom: .25em } - - .SClass, - .SDatabase, - .SDatabaseTable, - .SSection { - margin-top: 1em } - - .SMain .SEntry a, - .SClass .SEntry a, - .SDatabase .SEntry a, - .SDatabaseTable .SEntry a, - .SSection .SEntry a { color: #000000 } - - .SMain .SEntry a:active, - .SClass .SEntry a:active, - .SDatabase .SEntry a:active, - .SDatabaseTable .SEntry a:active, - .SSection .SEntry a:active { color: #A00000 } - - - - - -.ClassHierarchy { - margin: 0 15px 1em 15px } - - .CHEntry { - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0; - margin-bottom: 3px; - padding: 2px 2ex; - font-size: 10pt; - background-color: #F4F4F4; color: #606060; - } - - .Gecko .CHEntry { - -moz-border-radius: 4px; - } - - .CHCurrent .CHEntry { - font-weight: bold; - border-color: #000000; - color: #000000; - } - - .CHChildNote .CHEntry { - font-style: italic; - font-size: 8pt; - } - - .CHIndent { - margin-left: 3ex; - } - - .CHEntry a:link, - .CHEntry a:visited, - .CHEntry a:hover { - color: #606060; - } - .CHEntry a:active { - color: #800000; - } - - - - - -body.FramedIndexPage, -.IndexSection { - background-color: #FFFFFF; - font-size: 10pt; - padding: 15px } - -.IndexSection { - border-width: 0 0 1px 1px; border-style: solid; border-color: #000000 } - - .IPageTitle { - font-size: 20pt; font-weight: bold; - color: #FFFFFF; background-color: #7070C0; - padding: 10px 15px 10px 15px; - border-width: 0 0 3px 0; border-color: #000000; border-style: solid; - margin: -15px -15px 0 -15px } - - .INavigationBar { - text-align: center; - background-color: #FFFFF0; - padding: 5px; - border-bottom: solid 1px black; - margin: 0 -15px 15px -15px } - - .INavigationBar a { - font-weight: bold } - - .IHeading { - font-size: 16pt; font-weight: bold; - padding: 2.5em 0 .5em 0; - text-align: center; - width: 3.5ex; - } - #IFirstHeading { - padding-top: 0; - } - - .IEntry { - padding-left: 1ex; } - - .ISubIndex { - padding-left: 3ex; padding-bottom: .5em } - - /* While it may cause some entries to look like links when they aren't, I found it's much easier to read the - index if everything's the same color. */ - .ISymbol { - font-weight: bold; color: #900000 } - - .ISymbolPrefix { - text-align: right; - color: #C47C7C; - background-color: #F8F8F8; - border-right: 3px solid #E0E0E0; - border-left: 1px solid #E0E0E0; - padding: 0 1px 0 2px; - } - #IFirstSymbolPrefix { - border-top: 1px solid #E0E0E0; - } - #ILastSymbolPrefix { - border-bottom: 1px solid #E0E0E0; - } - #IOnlySymbolPrefix { - border-top: 1px solid #E0E0E0; - border-bottom: 1px solid #E0E0E0; - } - - a.IParent, - a.IFile { - display: block; - } - - - - -.Footer { - font-size: 8pt; color: #909090 } - -body.UnframedPage .Footer { - text-align: right; - margin: 2px } - -body.FramedMenuPage .Footer { - text-align: center; - margin: 5em 10px 0 10px} - - .Footer a:link, - .Footer a:hover, - .Footer a:visited { color: #909090 } - .Footer a:active { color: #A00000 } diff --git a/vendor/naturaldocs/Help/example/NaturalDocs.js b/vendor/naturaldocs/Help/example/NaturalDocs.js deleted file mode 100644 index 2af84cf54..000000000 --- a/vendor/naturaldocs/Help/example/NaturalDocs.js +++ /dev/null @@ -1,204 +0,0 @@ - -// -// Browser Styles -// ____________________________________________________________________________ - -var agt=navigator.userAgent.toLowerCase(); -var browserType; -var browserVer; - -if (agt.indexOf("opera") != -1) - { - browserType = "Opera"; - - if (agt.indexOf("opera 5") != -1 || agt.indexOf("opera/5") != -1) - { browserVer = "Opera5"; } - else if (agt.indexOf("opera 6") != -1 || agt.indexOf("opera/6") != -1) - { browserVer = "Opera6"; } - else if (agt.indexOf("opera 7") != -1 || agt.indexOf("opera/7") != -1) - { browserVer = "Opera7"; } - } - -else if (agt.indexOf("khtml") != -1 || agt.indexOf("konq") != -1 || agt.indexOf("safari") != -1) - { - browserType = "KHTML"; - } - -else if (agt.indexOf("msie") != -1) - { - browserType = "IE"; - - if (agt.indexOf("msie 4") != -1) - { browserVer = "IE4"; } - else if (agt.indexOf("msie 5") != -1) - { browserVer = "IE5"; } - else if (agt.indexOf("msie 6") != -1) - { browserVer = "IE6"; } - } - -else if (agt.indexOf("gecko") != -1) - { - browserType = "Gecko"; - } - -// Opera already taken care of. -else if (agt.indexOf("mozilla") != -1 && agt.indexOf("compatible") == -1 && agt.indexOf("spoofer") == -1 && - agt.indexOf("webtv") == -1 && agt.indexOf("hotjava") == -1) - { - browserType = "Netscape"; - - if (agt.indexOf("mozilla/4") != -1) - { browserVer = "Netscape4"; } - } - - -// -// Menu -// ____________________________________________________________________________ - - -function ToggleMenu(id) - { - if (!window.document.getElementById) - { return; }; - - var display = window.document.getElementById(id).style.display; - - if (display == "none") - { display = "block"; } - else - { display = "none"; } - - window.document.getElementById(id).style.display = display; - } - - -// -// Tooltips -// ____________________________________________________________________________ - - -var tooltipTimer = 0; - -function ShowTip(event, tooltipID, linkID) - { - if (tooltipTimer) - { clearTimeout(tooltipTimer); }; - - var docX = event.clientX + window.pageXOffset; - var docY = event.clientY + window.pageYOffset; - - var showCommand = "ReallyShowTip('" + tooltipID + "', '" + linkID + "', " + docX + ", " + docY + ")"; - - // KHTML cant handle showing on a timer right now. - - if (browserType != "KHTML") - { tooltipTimer = setTimeout(showCommand, 1000); } - else - { eval(showCommand); }; - } - -function ReallyShowTip(tooltipID, linkID, docX, docY) - { - tooltipTimer = 0; - - var tooltip; - var link; - - if (document.getElementById) - { - tooltip = document.getElementById(tooltipID); - link = document.getElementById(linkID); - } - else if (document.all) - { - tooltip = eval("document.all['" + tooltipID + "']"); - link = eval("document.all['" + linkID + "']"); - } - - if (tooltip) - { - var left = 0; - var top = 0; - - // Not everything supports offsetTop/Left/Width, and some, like Konqueror and Opera 5, think they do but do it badly. - - if (link && link.offsetWidth != null && browserType != "KHTML" && browserVer != "Opera5") - { - var item = link; - while (item != document.body) - { - left += item.offsetLeft; - item = item.offsetParent; - } - - item = link; - while (item != document.body) - { - top += item.offsetTop; - item = item.offsetParent; - } - top += link.offsetHeight; - } - - // The fallback method is to use the mouse X and Y relative to the document. We use a separate if and test if its a number - // in case some browser snuck through the above if statement but didn't support everything. - - if (!isFinite(top) || top == 0) - { - left = docX; - top = docY; - } - - // Some spacing to get it out from under the cursor. - - top += 10; - - // Make sure the tooltip doesnt get smushed by being too close to the edge, or in some browsers, go off the edge of the - // page. We do it here because Konqueror does get offsetWidth right even if it doesnt get the positioning right. - - if (tooltip.offsetWidth != null) - { - var width = tooltip.offsetWidth; - var docWidth = document.body.clientWidth; - - if (left + width > docWidth) - { left = docWidth - width - 1; } - } - - // Opera 5 chokes on the px extension, so it can use the Microsoft one instead. - - if (tooltip.style.left != null && browserVer != "Opera5") - { - tooltip.style.left = left + "px"; - tooltip.style.top = top + "px"; - } - else if (tooltip.style.pixelLeft != null) - { - tooltip.style.pixelLeft = left; - tooltip.style.pixelTop = top; - } - - tooltip.style.visibility = "visible"; - } - } - -function HideTip(tooltipID) - { - if (tooltipTimer) - { - clearTimeout(tooltipTimer); - tooltipTimer = 0; - } - - var tooltip; - - if (document.getElementById) - { tooltip = document.getElementById(tooltipID); } - else if (document.all) - { tooltip = eval("document.all['" + tooltipID + "']"); } - - if (tooltip) - { tooltip.style.visibility = "hidden"; } - } - diff --git a/vendor/naturaldocs/Help/example/Roman.css b/vendor/naturaldocs/Help/example/Roman.css deleted file mode 100644 index 54acc6e31..000000000 --- a/vendor/naturaldocs/Help/example/Roman.css +++ /dev/null @@ -1,507 +0,0 @@ -/* - IMPORTANT: If you're editing this file in the output directory of one of - your projects, your changes will be overwritten the next time you run - Natural Docs. Instead, copy this file to your project directory, make your - changes, and you can use it with -s. Even better would be to make a CSS - file in your project directory with only your changes, which you can then - use with -s [original style] [your changes]. - - On the other hand, if you're editing this file in the Natural Docs styles - directory, the changes will automatically be applied to all your projects - that use this style the next time Natural Docs is run on them. - - This file is part of Natural Docs, which is Copyright © 2003-2004 Greg Valure - Natural Docs is licensed under the GPL -*/ - -body { - font-family: "Times New Roman", Roman, serif; - color: #000000; - margin: 0px; padding: 0px } - -body.UnframedPage { - background-color: #E8E8E8 } - - -a:link, -a:visited { color: #900000; text-decoration: none } -a:hover { color: #900000; text-decoration: underline } -a:active { color: #FF0000; text-decoration: underline } - -td { - vertical-align: top } - -/* - Comment out this line to use web-style paragraphs (blank line between - paragraphs, no indent) instead of print-style paragraphs (no blank line, - indented.) -*/ -p { - text-indent: 5ex; margin: 0 } - - -/* Can't use something like display: none or it won't break. */ -.HB { - font-size: 1px } - - - - -body.FramedMenuPage, -.MenuSection { - font-size: 10pt; - background-color: #E8E8E8; - padding: 10px 0 0 0 } - -.MenuSection { - width: 27ex } - - - .MTitle { - font-size: 18pt; font-weight: bold; font-variant: small-caps; - text-align: center; - padding: 5px 10px 15px 10px; - border-bottom: 1px dotted #000000; - margin-bottom: 15px } - - .MSubTitle { - font-size: 10pt; font-weight: normal; font-variant: normal; - margin-top: 1ex; margin-bottom: 5px } - - - .MEntry a:link, - .MEntry a:hover, - .MEntry a:visited { color: #606060; margin-right: 0 } - .MEntry a:active { color: #A00000; margin-right: 0 } - - - .MGroup { - font-variant: small-caps; font-weight: bold; - margin: 1em 0 1em 10px } - - /* Konqueror just can't do margins. */ - .KHTML .MGroup { - margin-bottom: 0; padding-bottom: 1em } - - .MGroupContent { - font-variant: normal; font-weight: normal } - - .MGroup a:link, - .MGroup a:hover, - .MGroup a:visited { color: #545454; margin-right: 10px } - .MGroup a:active { color: #A00000; margin-right: 10px } - - - .MFile, - .MText, - .MLink, - .MIndex { - padding: 1px 17px 2px 10px; - margin: .25em 0 .25em 0 } - - .MText { - font-size: 8pt; font-style: italic } - - .MLink { - font-style: italic } - - #MSelected { - color: #000000; background-color: #FFFFFF; - /* Replace padding with border. */ - padding: 0 10px 0 10px; - border-width: 1px 2px 2px 0; border-style: solid; border-color: #000000; - margin-right: 5px } - - /* Close off the left side when its in a group. */ - .MGroup #MSelected { - padding-left: 9px; border-left-width: 1px } - - /* A treat for Mozilla users. Blatantly non-standard. Will be replaced with CSS 3 attributes when finalized/supported. */ - .Gecko #MSelected { - -moz-border-radius-topright: 10px; - -moz-border-radius-bottomright: 10px } - .Gecko .MGroup #MSelected { - -moz-border-radius-topleft: 10px; - -moz-border-radius-bottomleft: 10px } - - - - -body.FramedContentPage, -.ContentSection { - background-color: #FFFFFF; - padding-bottom: 15px } - -.ContentSection { - border-width: 0 0 1px 1px; border-style: solid; border-color: #000000 } - - - .CTopic { - font-size: 12pt; - /* This should be a margin but Konq 3.1.1 sucks. */ - padding-bottom: 3em } - - - .CTitle { - font-size: 16pt; font-weight: bold; - border-width: 0 0 1px 0; border-style: solid; border-color: #A0A0A0; - margin: 0 15px .5em 15px } - - .CGroup .CTitle { - font-size: 18pt; font-variant: small-caps; - padding-left: 15px; padding-right: 15px; - border-width: 0 0 2px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - .CClass .CTitle, - .CInterface .CTitle, - .CDatabase .CTitle, - .CDatabaseTable .CTitle, - .CSection .CTitle { - font-size: 20pt; - color: #FFFFFF; background-color: #A0A0A0; - padding: 10px 15px 10px 15px; - border-width: 2px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - #MainTopic .CTitle { - font-size: 24pt; - color: #FFFFFF; background-color: #7070C0; - padding: 10px 15px 10px 15px; - border-width: 0 0 3px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - .CBody { - margin-left: 15px; margin-right: 15px } - - - .CToolTip { - position: absolute; visibility: hidden; - left: 0; top: 0; max-width: 50%; - background-color: #FFFFE0; - padding: 5px; - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #000000; - font-size: 10pt } - - /* Opera 6 gives it a huge height otherwise. */ - .Opera6 .CTooltip, .Opera5 .CTooltip { - max-width: 100% } - - .CHeading { - font-weight: bold; - margin-top: 1.5em; margin-bottom: .5em } - - .CCode { - font: 10pt "Courier New", Courier, monospace; - overflow: auto; - } - - .CBulletList { - /* I don't know why CBody's margin doesn't apply, but it's consistent across browsers so whatever. - Reapply it here as padding. */ - padding-left: 15px; padding-right: 15px; - margin: .5em 5ex .5em 5ex; - } - - .CDescriptionList { - margin: .5em 5ex 0 5ex } - - /* IE 4 and Konqueror always makes it too long. */ - .IE4 .CDescriptionList, - .KHTML .CDescriptionList { - width: 85% } - - .CDLEntry { - font: 10pt "Courier New", Courier, monospace; color: #808080; - padding-bottom: .25em; - white-space: nowrap } - - .CDLDescription { - font-size: 12pt; /* For browsers that don't inherit correctly, like Opera 5. */ - padding-bottom: .5em; padding-left: 5ex } - - - - - -.Prototype { - font: 10pt "Courier New", Courier, monospace; - padding: 5px 3ex; - border-width: 1px; border-style: solid; - margin: 0 5ex 1.5em 5ex; - } - - .Prototype td { - font-size: 10pt; - } - - .PDefaultValue, - .PTypePrefix { - color: #8F8F8F; - } - .PTypePrefix { - text-align: right; - } - - .IE .Prototype table { - padding: 0; - } - - .CFunction .Prototype { - background-color: #F4F4F4; border-color: #D0D0D0 } - .CProperty .Prototype { - background-color: #F4F4FF; border-color: #C0C0E8 } - .CVariable .Prototype { - background-color: #FFFFF0; border-color: #E0E0A0 } - - .CDatabaseIndex .Prototype, - .CConstant .Prototype { - background-color: #D0D0D0; border-color: #000000 } - .CType .Prototype { - background-color: #FFF8F8; border-color: #E8C8C8 } - .CDatabaseTrigger .Prototype, - .CEvent .Prototype, - .CDelegate .Prototype { - background-color: #F0FCF0; border-color: #B8E4B8 } - - .CToolTip .Prototype { - margin: 0 0 .5em 0; - white-space: nowrap; - } - - - - - -.Summary { - margin: 1.5em 5ex 0 5ex } - - .STitle { - font-size: 14pt; font-weight: bold; - margin-bottom: .5em } - - - .SBorder { - background-color: #FFFFF0; - padding: 15px; - border: 1px solid #C0C060 } - - /* Let's observe the evolution of IE's brokeness, shall we? - IE 4 always makes them too long, there's no way around it. */ - .IE4 .SBorder { - width: 85% } - /* IE 5 will make them too long unless you set the width to 100%. Isn't this implied for a div? */ - .IE5 .SBorder { - width: 100% } - /* IE 6 behaves like 5 when it's in a frame, but without frames it will be correct without a width or slightly too long - (but not enough to scroll) with a width. This arbitrary weirdness simply astounds me. */ - body.FramedContentPage .IE6 .SBorder { - width: 100% } - - /* A treat for Mozilla users. Blatantly non-standard. Will be replaced with CSS 3 attributes when finalized/supported. */ - .Gecko .SBorder { - -moz-border-radius: 20px } - - - .STable { - font-size: 10pt; width: 100% } - - .SEntrySize { - width: 30% } - .SDescriptionSize { - width: 70% } - - - .SMarked { - background-color: #F8F8D8 } - - - .SEntry .SIndent1 { - margin-left: 1.5ex } - .SEntry .SIndent2 { - margin-left: 3ex } - .SEntry .SIndent3 { - margin-left: 4.5ex } - .SEntry .SIndent4 { - margin-left: 6ex } - .SEntry .SIndent5 { - margin-left: 7.5ex } - - .SDescription { - padding-left: 3ex } - - .SDescription a { color: #800000} - .SDescription a:active { color: #A00000 } - - - .SGroup { - margin-top: .5em; margin-bottom: .25em } - - .SGroup .SEntry { - font-weight: bold; font-variant: small-caps } - - .SGroup .SEntry a { color: #800000 } - .SGroup .SEntry a:active { color: #F00000 } - - - .SMain .SEntry, - .SClass .SEntry, - .SDatabase .SEntry, - .SDatabaseTable .SEntry, - .SSection .SEntry { - font-weight: bold; font-size: 12pt; - margin-bottom: .25em } - - .SClass, - .SDatabase, - .SDatabaseTable, - .SSection { - margin-top: 1em } - - .SMain .SEntry a, - .SClass .SEntry a, - .SDatabase .SEntry a, - .SDatabaseTable .SEntry a, - .SSection .SEntry a { color: #000000 } - - .SMain .SEntry a:active, - .SClass .SEntry a:active, - .SDatabase .SEntry a:active, - .SDatabaseTable .SEntry a:active, - .SSection .SEntry a:active { color: #A00000 } - - - - - -.ClassHierarchy { - margin: 0 15px 1em 15px } - - .CHEntry { - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0; - margin-bottom: 3px; - padding: 2px 2ex; - font-size: 12pt; - background-color: #F4F4F4; color: #606060; - } - - .Gecko .CHEntry { - -moz-border-radius: 4px; - } - - .CHCurrent .CHEntry { - font-weight: bold; - border-color: #000000; - color: #000000; - } - - .CHChildNote .CHEntry { - font-style: italic; - font-size: 8pt; - } - - .CHIndent { - margin-left: 3ex; - } - - .CHEntry a:link, - .CHEntry a:visited, - .CHEntry a:hover { - color: #606060; - } - .CHEntry a:active { - color: #800000; - } - - - - - -body.FramedIndexPage, -.IndexSection { - background-color: #FFFFFF; - font: 12pt "Times New Roman", serif; - padding: 15px } - -.IndexSection { - border-width: 0 0 1px 1px; border-style: solid; border-color: #000000 } - - .IPageTitle { - font-size: 24pt; font-weight: bold; - color: #FFFFFF; background-color: #7070C0; - padding: 10px 15px 10px 15px; - border-width: 0 0 3px 0; border-color: #000000; border-style: solid; - margin: -15px -15px 0 -15px } - - .INavigationBar { - text-align: center; - background-color: #FFFFF0; - padding: 5px; - border-bottom: solid 1px black; - margin: 0 -15px 15px -15px } - - .INavigationBar a { - font-weight: bold } - - .IHeading { - font-size: 20pt; font-weight: bold; - padding: 2.5em 0 .5em 0; - text-align: center; - width: 3.5ex; - } - #IFirstHeading { - padding-top: 0; - } - - .IEntry { - padding-left: 1ex; } - - .ISubIndex { - padding-left: 3ex; padding-bottom: .5em } - - /* While it may cause some entries to look like links when they aren't, I found it's much easier to read the - index if everything's the same color. */ - .ISymbol { - font-weight: bold; color: #900000 } - - .ISymbolPrefix { - text-align: right; - color: #C47C7C; - background-color: #F8F8F8; - border-right: 3px solid #E0E0E0; - border-left: 1px solid #E0E0E0; - padding: 0 1px 0 2px; - } - #IFirstSymbolPrefix { - border-top: 1px solid #E0E0E0; - } - #ILastSymbolPrefix { - border-bottom: 1px solid #E0E0E0; - } - #IOnlySymbolPrefix { - border-top: 1px solid #E0E0E0; - border-bottom: 1px solid #E0E0E0; - } - - a.IParent, - a.IFile { - display: block; - } - - - -.Footer { - font-size: 8pt; color: #909090 } - -body.UnframedPage .Footer { - text-align: right; - margin: 2px } - -body.FramedMenuPage .Footer { - text-align: center; - margin: 5em 10px 0 10px} - - .Footer a:link, - .Footer a:hover, - .Footer a:visited { color: #909090 } - .Footer a:active { color: #A00000 } diff --git a/vendor/naturaldocs/Help/example/Small.css b/vendor/naturaldocs/Help/example/Small.css deleted file mode 100644 index 0cb7be1c9..000000000 --- a/vendor/naturaldocs/Help/example/Small.css +++ /dev/null @@ -1,507 +0,0 @@ -/* - IMPORTANT: If you're editing this file in the output directory of one of - your projects, your changes will be overwritten the next time you run - Natural Docs. Instead, copy this file to your project directory, make your - changes, and you can use it with -s. Even better would be to make a CSS - file in your project directory with only your changes, which you can then - use with -s [original style] [your changes]. - - On the other hand, if you're editing this file in the Natural Docs styles - directory, the changes will automatically be applied to all your projects - that use this style the next time Natural Docs is run on them. - - This file is part of Natural Docs, which is Copyright © 2003-2004 Greg Valure - Natural Docs is licensed under the GPL -*/ - -body { - font-family: Verdana, Arial, sans-serif; - color: #000000; - margin: 0px; padding: 0px } - -body.UnframedPage { - background-color: #E8E8E8 } - - -a:link, -a:visited { color: #900000; text-decoration: none } -a:hover { color: #900000; text-decoration: underline } -a:active { color: #FF0000; text-decoration: underline } - -td { - vertical-align: top } - -/* - Comment out this line to use web-style paragraphs (blank line between - paragraphs, no indent) instead of print-style paragraphs (no blank line, - indented.) -*/ -p { - text-indent: 5ex; margin: 0 } - - -/* Can't use something like display: none or it won't break. */ -.HB { - font-size: 1px } - - - - -body.FramedMenuPage, -.MenuSection { - font-size: 8pt; - background-color: #E8E8E8; - padding: 10px 0 0 0 } - -.MenuSection { - width: 27ex } - - - .MTitle { - font-size: 16pt; font-weight: bold; font-variant: small-caps; - text-align: center; - padding: 5px 10px 15px 10px; - border-bottom: 1px dotted #000000; - margin-bottom: 15px } - - .MSubTitle { - font-size: 9pt; font-weight: normal; font-variant: normal; - margin-top: 1ex; margin-bottom: 5px } - - - .MEntry a:link, - .MEntry a:hover, - .MEntry a:visited { color: #606060; margin-right: 0 } - .MEntry a:active { color: #A00000; margin-right: 0 } - - - .MGroup { - font-variant: small-caps; font-weight: bold; - margin: 1em 0 1em 10px } - - /* Konqueror just can't do margins. */ - .KHTML .MGroup { - margin-bottom: 0; padding-bottom: 1em } - - .MGroupContent { - font-variant: normal; font-weight: normal } - - .MGroup a:link, - .MGroup a:hover, - .MGroup a:visited { color: #545454; margin-right: 10px } - .MGroup a:active { color: #A00000; margin-right: 10px } - - - .MFile, - .MText, - .MLink, - .MIndex { - padding: 1px 17px 2px 10px; - margin: .25em 0 .25em 0 } - - .MText { - font-size: 8pt; font-style: italic } - - .MLink { - font-style: italic } - - #MSelected { - color: #000000; background-color: #FFFFFF; - /* Replace padding with border. */ - padding: 0 10px 0 10px; - border-width: 1px 2px 2px 0; border-style: solid; border-color: #000000; - margin-right: 5px } - - /* Close off the left side when its in a group. */ - .MGroup #MSelected { - padding-left: 9px; border-left-width: 1px } - - /* A treat for Mozilla users. Blatantly non-standard. Will be replaced with CSS 3 attributes when finalized/supported. */ - .Gecko #MSelected { - -moz-border-radius-topright: 10px; - -moz-border-radius-bottomright: 10px } - .Gecko .MGroup #MSelected { - -moz-border-radius-topleft: 10px; - -moz-border-radius-bottomleft: 10px } - - - - -body.FramedContentPage, -.ContentSection { - background-color: #FFFFFF; - padding-bottom: 15px } - -.ContentSection { - border-width: 0 0 1px 1px; border-style: solid; border-color: #000000 } - - - .CTopic { - font-size: 8pt; - /* This should be a margin but Konq 3.1.1 sucks. */ - padding-bottom: 3em } - - - .CTitle { - font-size: 11pt; font-weight: bold; - border-width: 0 0 1px 0; border-style: solid; border-color: #A0A0A0; - margin: 0 15px .5em 15px } - - .CGroup .CTitle { - font-size: 16pt; font-variant: small-caps; - padding-left: 15px; padding-right: 15px; - border-width: 0 0 2px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - .CClass .CTitle, - .CInterface .CTitle, - .CDatabase .CTitle, - .CDatabaseTable .CTitle, - .CSection .CTitle { - font-size: 18pt; - color: #FFFFFF; background-color: #A0A0A0; - padding: 10px 15px 10px 15px; - border-width: 2px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - #MainTopic .CTitle { - font-size: 20pt; - color: #FFFFFF; background-color: #7070C0; - padding: 10px 15px 10px 15px; - border-width: 0 0 3px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - .CBody { - margin-left: 15px; margin-right: 15px } - - - .CToolTip { - position: absolute; visibility: hidden; - left: 0; top: 0; max-width: 50%; - background-color: #FFFFE0; - padding: 5px; - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #000000; - font-size: 8pt } - - /* Opera 6 gives it a huge height otherwise. */ - .Opera6 .CTooltip, .Opera5 .CTooltip { - max-width: 100% } - - .CHeading { - font-weight: bold; font-size: 9pt; - margin-top: 1.5em; margin-bottom: .5em } - - .CCode { - font: 8pt "Courier New", Courier, monospace; - overflow: auto; - } - - .CBulletList { - /* I don't know why CBody's margin doesn't apply, but it's consistent across browsers so whatever. - Reapply it here as padding. */ - padding-left: 15px; padding-right: 15px; - margin: .5em 5ex .5em 5ex; - } - - .CDescriptionList { - margin: .5em 5ex 0 5ex } - - /* IE 4 and Konqueror always makes it too long. */ - .IE4 .CDescriptionList, - .KHTML .CDescriptionList { - width: 85% } - - .CDLEntry { - font: 8pt "Courier New", Courier, monospace; color: #808080; - padding-bottom: .25em; - white-space: nowrap } - - .CDLDescription { - font-size: 8pt; /* For browsers that don't inherit correctly, like Opera 5. */ - padding-bottom: .5em; padding-left: 5ex } - - - - - -.Prototype { - font: 8pt "Courier New", Courier, monospace; - padding: 5px 3ex; - border-width: 1px; border-style: solid; - margin: 0 5ex 1.5em 5ex; - } - - .Prototype td { - font-size: 8pt; - } - - .PDefaultValue, - .PTypePrefix { - color: #8F8F8F; - } - .PTypePrefix { - text-align: right; - } - - .IE .Prototype table { - padding: 0; - } - - .CFunction .Prototype { - background-color: #F4F4F4; border-color: #D0D0D0 } - .CProperty .Prototype { - background-color: #F4F4FF; border-color: #C0C0E8 } - .CVariable .Prototype { - background-color: #FFFFF0; border-color: #E0E0A0 } - - .CDatabaseIndex .Prototype, - .CConstant .Prototype { - background-color: #D0D0D0; border-color: #000000 } - .CType .Prototype { - background-color: #FFF8F8; border-color: #E8C8C8 } - .CDatabaseTrigger .Prototype, - .CEvent .Prototype, - .CDelegate .Prototype { - background-color: #F0FCF0; border-color: #B8E4B8 } - - .CToolTip .Prototype { - margin: 0 0 .5em 0; - white-space: nowrap; - } - - - - - -.Summary { - margin: 1.5em 5ex 0 5ex } - - .STitle { - font-size: 11pt; font-weight: bold; - margin-bottom: .5em } - - - .SBorder { - background-color: #FFFFF0; - padding: 15px; - border: 1px solid #C0C060 } - - /* Let's observe the evolution of IE's brokeness, shall we? - IE 4 always makes them too long, there's no way around it. */ - .IE4 .SBorder { - width: 85% } - /* IE 5 will make them too long unless you set the width to 100%. Isn't this implied for a div? */ - .IE5 .SBorder { - width: 100% } - /* IE 6 behaves like 5 when it's in a frame, but without frames it will be correct without a width or slightly too long - (but not enough to scroll) with a width. This arbitrary weirdness simply astounds me. */ - body.FramedContentPage .IE6 .SBorder { - width: 100% } - - /* A treat for Mozilla users. Blatantly non-standard. Will be replaced with CSS 3 attributes when finalized/supported. */ - .Gecko .SBorder { - -moz-border-radius: 20px } - - - .STable { - font-size: 8pt; width: 100% } - - .SEntrySize { - width: 30% } - .SDescriptionSize { - width: 70% } - - - .SMarked { - background-color: #F8F8D8 } - - - .SEntry .SIndent1 { - margin-left: 1.5ex } - .SEntry .SIndent2 { - margin-left: 3ex } - .SEntry .SIndent3 { - margin-left: 4.5ex } - .SEntry .SIndent4 { - margin-left: 6ex } - .SEntry .SIndent5 { - margin-left: 7.5ex } - - .SDescription { - padding-left: 3ex } - - .SDescription a { color: #800000} - .SDescription a:active { color: #A00000 } - - - .SGroup { - margin-top: .5em; margin-bottom: .25em } - - .SGroup .SEntry { - font-weight: bold; font-variant: small-caps } - - .SGroup .SEntry a { color: #800000 } - .SGroup .SEntry a:active { color: #F00000 } - - - .SMain .SEntry, - .SClass .SEntry, - .SDatabase .SEntry, - .SDatabaseTable .SEntry, - .SSection .SEntry { - font-weight: bold; font-size: 9pt; - margin-bottom: .25em } - - .SClass, - .SDatabase, - .SDatabaseTable, - .SSection { - margin-top: 1em } - - .SMain .SEntry a, - .SClass .SEntry a, - .SDatabase .SEntry a, - .SDatabaseTable .SEntry a, - .SSection .SEntry a { color: #000000 } - - .SMain .SEntry a:active, - .SClass .SEntry a:active, - .SDatabase .SEntry a:active, - .SDatabaseTable .SEntry a:active, - .SSection .SEntry a:active { color: #A00000 } - - - - - -.ClassHierarchy { - margin: 0 15px 1em 15px } - - .CHEntry { - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0; - margin-bottom: 3px; - padding: 2px 2ex; - font-size: 8pt; - background-color: #F4F4F4; color: #606060; - } - - .Gecko .CHEntry { - -moz-border-radius: 4px; - } - - .CHCurrent .CHEntry { - font-weight: bold; - border-color: #000000; - color: #000000; - } - - .CHChildNote .CHEntry { - font-style: italic; - font-size: 8pt; - } - - .CHIndent { - margin-left: 3ex; - } - - .CHEntry a:link, - .CHEntry a:visited, - .CHEntry a:hover { - color: #606060; - } - .CHEntry a:active { - color: #800000; - } - - - - - -body.FramedIndexPage, -.IndexSection { - background-color: #FFFFFF; - font-size: 8pt; - padding: 15px } - -.IndexSection { - border-width: 0 0 1px 1px; border-style: solid; border-color: #000000 } - - .IPageTitle { - font-size: 20pt; font-weight: bold; - color: #FFFFFF; background-color: #7070C0; - padding: 10px 15px 10px 15px; - border-width: 0 0 3px 0; border-color: #000000; border-style: solid; - margin: -15px -15px 0 -15px } - - .INavigationBar { - text-align: center; - background-color: #FFFFF0; - padding: 5px; - border-bottom: solid 1px black; - margin: 0 -15px 15px -15px } - - .INavigationBar a { - font-weight: bold } - - .IHeading { - font-size: 14pt; font-weight: bold; - padding: 2.5em 0 .5em 0; - text-align: center; - width: 3.5ex; - } - #IFirstHeading { - padding-top: 0; - } - - .IEntry { - padding-left: 1ex; } - - .ISubIndex { - padding-left: 3ex; padding-bottom: .5em } - - /* While it may cause some entries to look like links when they aren't, I found it's much easier to read the - index if everything's the same color. */ - .ISymbol { - font-weight: bold; color: #900000 } - - .ISymbolPrefix { - text-align: right; - color: #C47C7C; - background-color: #F8F8F8; - border-right: 3px solid #E0E0E0; - border-left: 1px solid #E0E0E0; - padding: 0 1px 0 2px; - } - #IFirstSymbolPrefix { - border-top: 1px solid #E0E0E0; - } - #ILastSymbolPrefix { - border-bottom: 1px solid #E0E0E0; - } - #IOnlySymbolPrefix { - border-top: 1px solid #E0E0E0; - border-bottom: 1px solid #E0E0E0; - } - - a.IParent, - a.IFile { - display: block; - } - - - -.Footer { - font-size: 8pt; color: #909090 } - -body.UnframedPage .Footer { - text-align: right; - margin: 2px } - -body.FramedMenuPage .Footer { - text-align: center; - margin: 5em 10px 0 10px} - - .Footer a:link, - .Footer a:hover, - .Footer a:visited { color: #909090 } - .Footer a:active { color: #A00000 } diff --git a/vendor/naturaldocs/Help/example/showstyle.html b/vendor/naturaldocs/Help/example/showstyle.html deleted file mode 100644 index e71b8b9cd..000000000 --- a/vendor/naturaldocs/Help/example/showstyle.html +++ /dev/null @@ -1,43 +0,0 @@ - - -CSS Sample - Project - - - - - - - - - - - - - - -
This is the style.  Back
- - - - - - -

CSS Sample

Here’s what the output would look like with the currently selected CSS style.  The CSS structure is well-documented so you can easily alter it or make your own.

Here’s a paragraph break.  Natural Docs defaults to print-style paragraphs, where each one is indented rather than separated with a blank line.  If you open the CSS file it will tell you which line to remove to go back to web-style paragraphs.

Header

There’s a header, just so you know what one looks like in this style.  As you can tell, the quality of the text here is going to go downhill fast as I’m really just blathering on to fill up the page.  If you’re actually reading this, you can safely stop now.  No, really.  I’m not going to say anything important from here on down.  Reading it will be just as boring as writing it was.

  • Here’s a bullet.  Thought you should see that.
  • Here’s another one.  Well look at that.
  • And a third.  Looks just like all the others, but I’m going to give it some more text.  So there you go.

Now lets look at a text diagram, shall we?  Are you still reading this?  What’s wrong with you?

+------+     +------+
-| Moby | --> | Dick |
-+------+     +------+
-   |
-   V
-+----------+
-| Musician |
-+----------+
Summary
Here’s what the output would look like with the currently selected CSS style.
Ah, here’s our first function.
This is another function, much like DoSomething(), but different, in that it does something else.
This is my variable.

DoSomething

int DoSomething(int one,
int two,
float four)

Ah, here’s our first function.  I have nothing to say about it just like I had nothing to say about anything else.  Typing, typing, typing to fill up space.  Just a random stream-of-consciousness about nothing.

Parameters

oneThis is the first parameter, aptly named one.
twoBet you can’t guess what the next one is called?
fourHah!  Did that just to screw you up.

Returns

Sometimes it returns, sometimes it doesn’t.  It’s moody that way.

DoSomethingElse

bool DoSomethingElse()

This is another function, much like DoSomething(), but different, in that it does something else.  Hover over DoSomething(), will ya?  See the nice DHTML tooltip goodness.  Here, here’s a link to myVariable too.  Hover over that.

Variables

myVariable

int myVariable

This is my variable.  See how the prototype is colored differently on the default styles?  I thought that was cool too, since you can tell where you are in the documentation easier.  Or maybe you didn’t think it was cool.  I shouldn’t make assumptions like that.  See, now you went and hurt my feelings.  Shame on you.

Um, why are you still reading this?  Didn’t you learn by now?

int DoSomething(int one,
int two,
float four)
Ah, here’s our first function.
bool DoSomethingElse()
This is another function, much like DoSomething(), but different, in that it does something else.
int myVariable
This is my variable.
diff --git a/vendor/naturaldocs/Help/examples.css b/vendor/naturaldocs/Help/examples.css deleted file mode 100644 index f61d06b6d..000000000 --- a/vendor/naturaldocs/Help/examples.css +++ /dev/null @@ -1,90 +0,0 @@ -@import URL(example/Default.css); - - -.NDContent { - color: #000000; background-color: #FFFFFF; - padding: 15px 0; - border-style: solid; - border-width: 1px 3px 3px 1px; - border-color: #c0c0c0 #808080 #808080 #c0c0c0; - margin: 1em 5ex; - -moz-border-radius: 12px; - } - - .NDContent p, - .NDContent li, - .NDContent td, - .NDMenu td, - .NDSummary td, - .NDIndex td { - font-size: 10pt; - line-height: normal; - } - .NDContent .CTopic { - padding-bottom: 0; - } - .Prototype td { - font: 10pt Courier New, monospace; - } - .NDIndex .IHeading { - font-size: 16pt; - } - - -.NDMenu { - font: 9pt Verdana, Arial, sans-serif; - color: #000000; background-color: #E8E8E8; - width: 27ex; - padding: 10px 0; - border-style: solid; - border-width: 1px 3px 3px 1px; - border-color: #808080 #606060 #606060 #808080; - margin: 1em 0 1em 5ex; - -moz-border-radius: 12px; - } - - -.NDFooter { - font: 8pt Verdana, Arial, sans-serif; - color: #909090; background-color: #E8E8E8; - border-style: solid; - border-width: 1px 3px 3px 1px; - border-color: #808080 #606060 #606060 #808080; - margin: 1em 0 1em 5ex; - -moz-border-radius: 12px; - } -.NDFooter td { - font-size: 8pt; - padding: 0 2ex; - } - - .NDFooter a:link, - .NDFooter a:hover, - .NDFooter a:visited { color: #909090 } - .NDFooter a:active { color: #A00000 } - - -.NDSummary { - padding: 15px; - border-style: solid; - border-width: 1px 3px 3px 1px; - border-color: #c0c0c0 #808080 #808080 #c0c0c0; - margin: 1em 5ex; - -moz-border-radius: 12px; - } - - .NDSummary .Summary { - margin-top: 0; - } - - -.NDIndex { - color: #000000; background-color: #FFFFFF; - padding: 15px; - border-style: solid; - border-width: 1px 3px 3px 1px; - border-color: #c0c0c0 #808080 #808080 #c0c0c0; - margin: 1em 5ex; - -moz-border-radius: 12px; - } - diff --git a/vendor/naturaldocs/Help/images/header/background.png b/vendor/naturaldocs/Help/images/header/background.png deleted file mode 100644 index 09a2ea465..000000000 Binary files a/vendor/naturaldocs/Help/images/header/background.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/header/leftside.png b/vendor/naturaldocs/Help/images/header/leftside.png deleted file mode 100644 index 7d0938657..000000000 Binary files a/vendor/naturaldocs/Help/images/header/leftside.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/header/logo.png b/vendor/naturaldocs/Help/images/header/logo.png deleted file mode 100644 index 9317a1b69..000000000 Binary files a/vendor/naturaldocs/Help/images/header/logo.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/header/overbody.png b/vendor/naturaldocs/Help/images/header/overbody.png deleted file mode 100644 index 6b86af15f..000000000 Binary files a/vendor/naturaldocs/Help/images/header/overbody.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/header/overbodybg.png b/vendor/naturaldocs/Help/images/header/overbodybg.png deleted file mode 100644 index b4284ec19..000000000 Binary files a/vendor/naturaldocs/Help/images/header/overbodybg.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/header/overleftmargin.png b/vendor/naturaldocs/Help/images/header/overleftmargin.png deleted file mode 100644 index 3d02af7fa..000000000 Binary files a/vendor/naturaldocs/Help/images/header/overleftmargin.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/header/overmenu.png b/vendor/naturaldocs/Help/images/header/overmenu.png deleted file mode 100644 index d720d9860..000000000 Binary files a/vendor/naturaldocs/Help/images/header/overmenu.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/header/overmenubg.png b/vendor/naturaldocs/Help/images/header/overmenubg.png deleted file mode 100644 index 69339d8cb..000000000 Binary files a/vendor/naturaldocs/Help/images/header/overmenubg.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/header/rightside.png b/vendor/naturaldocs/Help/images/header/rightside.png deleted file mode 100644 index f8ef976a4..000000000 Binary files a/vendor/naturaldocs/Help/images/header/rightside.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/menu/about.png b/vendor/naturaldocs/Help/images/menu/about.png deleted file mode 100644 index ca65ea4e7..000000000 Binary files a/vendor/naturaldocs/Help/images/menu/about.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/menu/background.png b/vendor/naturaldocs/Help/images/menu/background.png deleted file mode 100644 index db8b557bb..000000000 Binary files a/vendor/naturaldocs/Help/images/menu/background.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/menu/bottomleft.png b/vendor/naturaldocs/Help/images/menu/bottomleft.png deleted file mode 100644 index 0f608c8b9..000000000 Binary files a/vendor/naturaldocs/Help/images/menu/bottomleft.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/menu/bottomright.png b/vendor/naturaldocs/Help/images/menu/bottomright.png deleted file mode 100644 index 10c9e0291..000000000 Binary files a/vendor/naturaldocs/Help/images/menu/bottomright.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/menu/community.png b/vendor/naturaldocs/Help/images/menu/community.png deleted file mode 100644 index 0021013ac..000000000 Binary files a/vendor/naturaldocs/Help/images/menu/community.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/menu/customizing.png b/vendor/naturaldocs/Help/images/menu/customizing.png deleted file mode 100644 index d56d25b3f..000000000 Binary files a/vendor/naturaldocs/Help/images/menu/customizing.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/images/menu/using.png b/vendor/naturaldocs/Help/images/menu/using.png deleted file mode 100644 index 1de988d2c..000000000 Binary files a/vendor/naturaldocs/Help/images/menu/using.png and /dev/null differ diff --git a/vendor/naturaldocs/Help/index.html b/vendor/naturaldocs/Help/index.html deleted file mode 100644 index 84a7b633b..000000000 --- a/vendor/naturaldocs/Help/index.html +++ /dev/null @@ -1,9 +0,0 @@ - - -Natural Docs - - - -
Natural Docs
Version 1.51

This is the Natural Docs help file, a subset of the documentation available at the web site.  Everything you need is on the menu to the left.

Copyright © 2003-2010 Greg Valure
\ No newline at end of file diff --git a/vendor/naturaldocs/Help/javascript/BrowserStyles.js b/vendor/naturaldocs/Help/javascript/BrowserStyles.js deleted file mode 100644 index 71666418d..000000000 --- a/vendor/naturaldocs/Help/javascript/BrowserStyles.js +++ /dev/null @@ -1,77 +0,0 @@ - -// -// Browser Styles -// ____________________________________________________________________________ - -var agt=navigator.userAgent.toLowerCase(); -var browserType; -var browserVer; - -if (agt.indexOf("opera") != -1) - { - browserType = "Opera"; - - if (agt.indexOf("opera 5") != -1 || agt.indexOf("opera/5") != -1) - { browserVer = "Opera5"; } - else if (agt.indexOf("opera 6") != -1 || agt.indexOf("opera/6") != -1) - { browserVer = "Opera6"; } - else if (agt.indexOf("opera 7") != -1 || agt.indexOf("opera/7") != -1) - { browserVer = "Opera7"; } - } - -else if (agt.indexOf("khtml") != -1 || agt.indexOf("konq") != -1 || agt.indexOf("safari") != -1) - { - browserType = "KHTML"; - } - -else if (agt.indexOf("msie") != -1) - { - browserType = "IE"; - - if (agt.indexOf("msie 4") != -1) - { browserVer = "IE4"; } - else if (agt.indexOf("msie 5") != -1) - { browserVer = "IE5"; } - else if (agt.indexOf("msie 6") != -1) - { browserVer = "IE6"; } - else if (agt.indexOf("msie 7") != -1) - { browserVer = "IE7"; } - } - -else if (agt.indexOf("gecko") != -1) - { - browserType = "Gecko"; - } - -// Opera already taken care of. -else if (agt.indexOf("mozilla") != -1 && agt.indexOf("compatible") == -1 && agt.indexOf("spoofer") == -1 && - agt.indexOf("webtv") == -1 && agt.indexOf("hotjava") == -1) - { - browserType = "Netscape"; - - if (agt.indexOf("mozilla/4") != -1) - { browserVer = "Netscape4"; } - } - - -function OpeningBrowserTags() - { - if (browserType) - { - document.write('
'); - - if (browserVer) - { document.write('
'); } - } - }; - -function ClosingBrowserTags() - { - if (browserType) - { - document.write('
'); - - if (browserVer) - { document.write('
'); } - } - }; diff --git a/vendor/naturaldocs/Help/javascript/PNGHandling.js b/vendor/naturaldocs/Help/javascript/PNGHandling.js deleted file mode 100644 index ab47a538e..000000000 --- a/vendor/naturaldocs/Help/javascript/PNGHandling.js +++ /dev/null @@ -1,72 +0,0 @@ -// Parts derived from: -// Opacity Displayer, Version 1.0 -// Copyright Michael Lovitt, 6/2002. -// Distribute freely, but please leave this notice intact. -// http://www.alistapart.com/articles/pngopacity/ - -// Parts derived from: -// Natural Docs -// Copyright (C) 2003-2004 Greg Valure -// http://www.naturaldocs.org/ - - -var pngTransform; -var pngNormal; - -var agt=navigator.userAgent.toLowerCase(); - -if (agt.indexOf("opera") != -1) - { - if ( (agt.indexOf("opera 5") != -1 || agt.indexOf("opera/5") != -1) && - agt.indexOf("mac") != -1) - { - pngNormal = 1; - } - else if (agt.indexOf("opera 6") != -1 || agt.indexOf("opera/6") != -1 || - agt.indexOf("opera 7") != -1 || agt.indexOf("opera/7") != -1) - { - pngNormal = 1; - } - } - -else if (agt.indexOf("msie") != -1) - { - if (agt.indexOf("msie 5.5") != -1 || agt.indexOf("msie 6") != -1) - { - if (agt.indexOf("mac") != -1) - { pngNormal = 1; } - else if (agt.indexOf("win") != -1) - { pngTransform = 1; }; - } - - else if (agt.indexOf("msie 5") != -1) - { - if (agt.indexOf("mac") != -1) - { pngNormal = 1; }; - } - - else if (agt.indexOf("msie 7") != -1) - { pngNormal = 1; } - } - -else if (agt.indexOf("gecko") != -1) - { - pngNormal = 1; - } - - -function PNGGIF(strPath, intWidth, intHeight, strAlt, strID) - { - if (pngTransform) - { - document.write('
'); - } - else if (pngNormal) - { - document.write(''+strAlt+''); - } - else - { - document.write(''+strAlt+''); - } - }; diff --git a/vendor/naturaldocs/Help/keywords.html b/vendor/naturaldocs/Help/keywords.html deleted file mode 100644 index 648250325..000000000 --- a/vendor/naturaldocs/Help/keywords.html +++ /dev/null @@ -1,38 +0,0 @@ - - -Natural Docs Topics and Keywords - - - -
Natural Docs
Topics and Keywords

Keywords are not case sensitive and are interchangable within their topic type.  The plural forms denote list topics where every item in its definition lists are treated like they have their own topic.

General Topics
Generic
topictopics
aboutlist
Section
Ends Scope
section
title
Group
group
File
Always Global
filefiles
programprograms
scriptscripts
documentdocuments
docdocs
headerheaders
Code Topics
Class
Starts Scope
classclasses
structurestructures
structstructs
packagepackages
namespacenamespaces
Interface
Starts Scope
interfaceinterfaces
Type
typetypes
typedeftypedefs
Constant
constantconstants
constconsts
Enumeration
Topic indexed under Types
Members indexed under Constants
enumerationenumerations
enumenums
Function
List topics break apart
functionfunctions
funcfuncs
procedureprocedures
procprocs
routineroutines
subroutinesubroutines
subsubs
methodmethods
callbackcallbacks
constructorconstructors
destructordestructors
operatoroperators
Property
propertyproperties
propprops
Event
eventevents
Delegate
delegatedelegates
Macro
macromacros
definedefines
defdefs
Variable
variablevariables
varvars
integerintegers
intints
uintuints
longlongs
ulongulongs
shortshorts
ushortushorts
bytebytes
ubyteubytes
sbytesbytes
floatfloats
doubledoubles
realreals
decimaldecimals
scalarscalars
arrayarrays
arrayrefarrayrefs
hashhashes
hashrefhashrefs
boolbools
booleanbooleans
flagflags
bitbits
bitfieldbitfields
fieldfields
pointerpointers
ptrptrs
referencereferences
refrefs
objectobjects
objobjs
charactercharacters
wcharacterwcharacters
charchars
wcharwchars
stringstrings
wstringwstrings
strstrs
wstrwstrs
handlehandles
Database Topics
Database
databasedatabases
dbdbs
Database Table
Starts Scope
tabletables
database tabledatabase tables
db tabledb tables
Database View
Starts Scope
viewviews
database viewdatabase views
db viewdb views
Database Cursor
cursorcursors
database cursordatabase cursors
db cursordb cursors
Database Index
indexindexes
indices
database indexdatabase indexes
database indices
db indexdb indexes
db indices
keykeys
database keydatabase keys
db keydb keys
primary keyprimary keys
database primary keydatabase primary keys
db primary keydb primary keys
Database Trigger
triggertriggers
database triggerdatabase triggers
db triggerdb triggers
Miscellaneous Topics
Cookie
Always global
cookiecookies
Build Target
targettargets
build targetbuild targets
Copyright © 2003-2010 Greg Valure
\ No newline at end of file diff --git a/vendor/naturaldocs/Help/languages.html b/vendor/naturaldocs/Help/languages.html deleted file mode 100644 index 02f21a09a..000000000 --- a/vendor/naturaldocs/Help/languages.html +++ /dev/null @@ -1,32 +0,0 @@ - - -Natural Docs Language Support - - - -
Natural Docs
About
Language SupportOutput Formats
Language Support
Full Language Support

The following languages have full language support, which means you get:

Full code documentation.  All functions, variables, and classes will appear in the output regardless of whether you wrote anything for them.  This can be turned off with the -do command line option.

Inheritance diagrams.  They will appear in the output wherever appropriate.

Javadoc compatibility.  Natural Docs can read most Javadoc comments and include them in the output.  You can also write Natural Docs documentation without topic lines by using the Javadoc comment symbols.

Auto-scoping.  The class a topic is part of is determined by the source code rather than class and section topics.

  • C# (1.1, some 2.0)
  • Perl
  • ActionScript (2 and 3)
Basic Language Support

The following languages have basic language support, which means you have:

Explicit documentation only.  Only things you write Natural Docs documentation for will appear in the output.

No inheritance diagrams.

Natural Docs comments only.  They also need to include a topic line.

Topic scoping.  The class a topic is part of is determined by the topic scoping rules.

  • C/C++
  • Java
  • PHP
  • Python
  • PL/SQL
  • Visual Basic
  • Pascal/Delphi
  • Ada
  • JavaScript
  • Ruby
  • Tcl
  • ColdFusion
  • Assembly
  • Fortran (free-format only)
  • R
  • Makefiles
  • Plain Text
  • Custom Languages
Copyright © 2003-2010 Greg Valure
\ No newline at end of file diff --git a/vendor/naturaldocs/Help/menu.html b/vendor/naturaldocs/Help/menu.html deleted file mode 100644 index ef087d23a..000000000 --- a/vendor/naturaldocs/Help/menu.html +++ /dev/null @@ -1,79 +0,0 @@ - - -Organizing the Menu - Natural Docs - - - -
Natural Docs
Organizing the Menu

Natural Docs creates a file called Menu.txt in your project directory that you can edit to organize the menu.  It normally takes care of this on its own, but you have the option of improving it manually if you want to.

Order and Titles

If you’ve never looked in it before, the menu file will have some comments explaining its syntax and a list like you see below.

File: ClassA  (ClassA.h)
-File: ClassB  (ClassB.h)
-File: Globals  (Globals.h)
-

The list gets turned into a menu that looks like this:

The lines are in the format “File: [title] ([filename])”.  When Natural Docs made the menu, it decided on its own what the title of each file should be and then put them in alphabetical order.  However, suppose we don’t want this.  We want Globals above the classes and we want spaces in the menu titles.  So we edit the file.

File: Globals  (Globals.h)
-File: Class A  (ClassA.h)
-File: Class B  (ClassB.h)
-

Run Natural Docs again and the menu is updated.

However, open the menu file again and you’ll see something interesting.

File: Globals  (Globals.h)
-File: Class A  (no auto-title, ClassA.h)
-File: Class B  (no auto-title, ClassB.h)
-

Natural Docs noticed that you changed a couple of the titles and added a no auto-title attribute to each one.  This tells it to never change them on it’s own in the future, so your changes won’t be lost.  You don’t have to worry about adding this, Natural Docs will always do it automatically.  However, to go back to automatic titles you’d have to manually remove it.

Grouping

This menu is good for our example, but in the real world they get much, much longer.  We can add groups to organize it further.  Natural Docs will create them automatically based on the each file’s directory, but once again you can improve it manually if that’s not good enough.

You can add groups as shown below.

File: Globals  (Globals.h)
-Group: Classes {
-   File: Class A  (no auto-title, ClassA.h)
-   File: Class B  (no auto-title, ClassB.h) }
-

You can also nest them inside each other.

File: Globals  (Globals.h)
-Group: Classes {
-   File: Class A  (no auto-title, ClassA.h)
-   Group: Nested Group {
-      File: Class B  (no auto-title, ClassB.h)  }
-   }
-

We’ll get rid of the nested group because it doesn’t make sense for our example.  Run Natural Docs, open up the menu file again and take a look.

File: Globals  (Globals.h)
-
-Group: Classes  {
-
-   File: Class A  (no auto-title, ClassA.h)
-   File: Class B  (no auto-title, ClassB.h)
-   }  # Group: Classes
-

Natural Docs reformatted it.  When you’re organizing the menu, you don’t have to worry about the indentation or otherwise keeping it neat.  The file is reformatted every time it changes, so you can make quick and dirty edits and Natural Docs will keep it readable.

Besides breaking up long lists, groups also serve another purpose.  Clicking on them will make it expand and collapse.  Go ahead and try it in the examples above.  When the menu gets too long its groups will start being collapsed by default, allowing easier navigation on large projects where it would just be impractical to show everything at once.

Indexes and Search

Natural Docs will automatically determine what indexes your project needs and add them to the menu.  Anything indexed will also be used for the search feature.  The entries will look like this:

Group: Index {
-
-   Index: Everything
-   Class Index: Classes
-   Function Index: Functions
-   }  # Group: Index
-

Like the file entries we saw before, you can rename them by editing the title and reorder them by cutting and pasting.  However, if you decide you don’t want a particular index to be generated, just delete its entry and it will go away.  Just like before, Natural Docs will detect this and add something new:

Don't Index: Functions
-

As with no auto-title, Natural Docs adds this automatically to make sure it doesn’t later undo your changes.

Automatic Changes

Natural Docs tries to manage the menu on its own as much as possible so you don’t have to worry about it.  This is just a peek into some of the things it does so you know what to expect.

You already saw that by default Natural Docs tries to guess what title should be for each file.  If you leave it this way, Natural Docs will always update the menu for you if the file’s content changes significantly enough to change its guess, such as if you rename the first class defined in it.  If you’d like to take advantage of this to define the menu title in each source file instead of in the menu itself, add a “Title: [title]” comment to the top of the file.

When you add and delete source files, Natural Docs will automatically add and remove them from the menu file.  When adding one it will look for the best group to put it in by directory.  If your grouping mirrors the source tree somewhat, this will be a lot more accurate.  Also, if the group it’s putting it in is alphabetized, Natural Docs will put it in the correct place to maintain that alphabetization.  In fact, even if an existing file’s automatic title changes, it will change it’s position to make sure a previously alphabetized group stays that way.

There are exceptions in alphabetization for the indexes.  If a group only contains indexes, it can be the last item on the menu or in its parent group without making it count as unsorted.  Also, within groups that only contain indexes, the general index can be first, also without making the group count as unsorted.

Finally, if Natural Docs adds some files to a group that causes it to become too long, it will attempt to sub-group it based on directory.  However, it will only do this when its adding files on its own, so you don’t have to worry about it constantly messing up your groups.  Since new files aren’t added to a project that often, if you change the menu manually it should stay that way for quite some time.

Extras

There’s more you can do with the menu than just renaming and reorganizing its entries.  Natural Docs has a few extras you can add to it as well.

Title and Subtitle

You can add a title and subtitle to your menu.

Title: My Project
-SubTitle: Something That Does Something
-
-File: Globals  (Globals.h)
-Group: Classes
-   File: Class A  (no auto-title, ClassA.h)
-   File: Class B  (no auto-title, ClassB.h)
-
My Project
Something That Does Something

In addition to adding the title to the menu, the Title tag will also change the HTML page titles from “Class A” to “Class A - My Project”, making bookmarks clearer.

Text and Web Links

You can also add arbitrary text and web links to your menu.

File: Globals  (Globals.h)
-Group: Classes  {
-   Text: I couldn't think of good names for these classes.
-   File: Class A  (no auto-title, ClassA.h)
-   File: Class B  (no auto-title, ClassB.h)
-   }
-Link: Built with Natural Docs  (http://www.naturaldocs.org)
-
Classes

Even though comments use the # character, adding an anchor to a link (such as “http://www.website.com/page.html#anchor”) will still work.

Footers

Finally, you can add a footer to all your pages, such as a copyright notice.  Natural Docs will change any (c)’s it finds into real copyright symbols.

Footer: Copyright (C) 2010 Me
-
Copyright © 2010 Me  ·  Generated by Natural Docs

You can also add a timestamp in any format you want.  The tokens you can use in building it are:

mOne or two digit month.January is “1”
mmAlways two digit month.January is “01”
monShort month word.January is “Jan”
monthLong month word.January is “January”
dOne or two digit day.1 is “1”
ddAlways two digit day.1 is “01”
dayDay with letter extension.1 is “1st”
yyTwo digit year.2010 is “10”
yyyyFour digit year.2010 is “2010”
yearFour digit year.2010 is “2010”

Everything else appears literally, so we can add:

Timestamp: Updated month day, year
-

and get:

Copyright © 2010 Me  ·  Updated January 1st, 2010  ·  Generated by Natural Docs
Errors

If there’s ever an error in the menu file, Natural Docs will tell you when it’s run.  It also adds a comment for each one in the menu file itself so that you can search for them in a text editor.

# There is an error in this file.  Search for ERROR to find it.
-
-File: Globals  (Globals.h)
-Group: Classes  {
-# ERROR: Txet is not a valid keyword.
-   Txet: I couldn't think of good names for these classes.
-   File: Class A  (no auto-title, ClassA.h)
-   File: Class B  (no auto-title, ClassB.h)
-   }
-

Remember that Natural Docs reformats the menu file whenever it’s run, so you only need to correct the error.  Natural Docs will remove the error comments on its own.

Portability and Versioning Systems

If you only use one input directory, all the files in the menu will have relative paths.  However, if you have more Natural Docs will use the absolute path instead.

This is not a problem.  The menu file can still be shared between machines even if they don’t keep the source tree in the exact same location.  As long as you have the same layout within the source tree and point to the same base directories in the command line, Natural Docs will be able to convert the paths automatically for the new machine.

However, if you’re putting the menu file in a versioning system like Subversion or SourceSafe, it might be very desirable to only have relative paths so anybody can check it in and only the real changes show.  In that case, instead of using multiple input directories, see if it’s possible to only have one input directory and use the -xi command line option to exclude the subdirectories you don’t want scanned.

That’s It!

And we’re done.  The syntax to do all of this is included in the menu file itself, so you don’t need to memorize everything.  You shouldn’t need to organize the menu very often, just after a lot of new files have been added and if you don’t like the default.

Note that if you’re using the non-framed HTML output format, changing the menu does require every output file to be updated.  However, Natural Docs has a special process just for this so it won’t take nearly as long as if it were rebuilding them all from scratch.  Still, if you’re working on a large project, it may be worth considering the framed HTML output format.

Copyright © 2003-2010 Greg Valure
\ No newline at end of file diff --git a/vendor/naturaldocs/Help/output.html b/vendor/naturaldocs/Help/output.html deleted file mode 100644 index 7d1bcda9b..000000000 --- a/vendor/naturaldocs/Help/output.html +++ /dev/null @@ -1,84 +0,0 @@ - - -Output Formats - Natural Docs - - - -
Natural Docs
About
Language SupportOutput Formats
Output Formats

These are the output formats that are currently implemented in Natural Docs.

HTMLHTML output.  Each page is self-contained.  Linking to specific pages is easy, but every file has to be updated whenever the menu changes.
FramedHTMLHTML output based on frames.  The menu is updated quickly, but linking to individual pages is difficult and some people just plain hate frames.
HTML Compatibility

These are the browsers Natural Docs’ HTML output has been tested with.  All browsers will be able to view and navigate it, some of the older ones just may not be able to use advanced features like search correctly.

FireFoxTested with 1.0, 1.5, and 2.0.
Internet ExplorerTested with 6 and 7.
SafariTested with 2 and 3.  Search doesn’t work with unframed HTML in 2.
OperaTested with 7.0, 7.5, 8.0, 8.5, and 9.0.  Search doesn’t work with 7.0, and sometimes tooltips.
KonquerorTested with 3.5.5.  Search doesn’t work.
Copyright © 2003-2010 Greg Valure
\ No newline at end of file diff --git a/vendor/naturaldocs/Help/running.html b/vendor/naturaldocs/Help/running.html deleted file mode 100644 index df186563c..000000000 --- a/vendor/naturaldocs/Help/running.html +++ /dev/null @@ -1,40 +0,0 @@ - - -Running Natural Docs - - - -
Natural Docs
Running Natural Docs
 
How and When

Probably the best way to run Natural Docs is as part of the build process.  This way every time you compile your code, your documentation is updated as well and you always have a current reference.  Natural Docs has a differential build process so it will not rebuild the entire set of documentation every time it’s run.

If you’d like to run it manually instead, you should determine the command line you need and save it as a shortcut, batch file, or script since you should be running it often and will rarely need to fiddle with the parameters.

Command Line
NaturalDocs -i [input (source) directory]
-            -o [output format] [output directory]
-            -p [project directory]
-            [options]
Required Parameters:
-i [dir]
--input [dir]
--source [dir]

The input (source) directory.  Natural Docs will build the documentation from the files in this directory and all its subdirectories.  You can specify it multiple times to include multiple directories.  See the list of supported programming languages.

-o [fmt] [dir]
--output [fmt] [dir]

The output format and directory.  This can also be specified multiple times, so you can build the documentation in multiple formats in a single run.  The supported formats are HTML and FramedHTML.

-p [dir]
--project [dir]

The project directory.  Natural Docs needs a place to store configuration and data files for each project it’s run on, so this is where it will put them.  No two projects should share the same directory.

Optional Parameters:
-xi [dir]
--exclude-input [dir]
--exclude-source [dir]

Excludes a subdirectory from being scanned.  The output and project directories are automatically excluded.

-img [dir]
--images [dir]

Adds a directory to search for image files when using (see [file]).

-s [style] ([style] ...)
--style [style] ([style] ...)

Selects the CSS style for HTML output.  The default styles are Default, Small, and Roman.

You can use any CSS file in your project directory or Natural Docs’ Styles directory just by using its name without the .css extension.  If you include more than one, they will all be included in the HTML that order.

-r
--rebuild

Rebuilds everything from scratch.  All source files will be rescanned and all output files will be rebuilt

-ro
--rebuild-output

Rebuilds all output files from scratch.

-t [len]
--tab-length [len]

Sets the number of spaces tabs should be expanded to.  This only needs to be set if you use tabs in example code or text diagrams.  The default is 4.

-hl [opt]
--highlight [opt]

Sets the syntax highlighting option used in the output.  Off turns off all syntax highlighting.  Code applies it to prototypes and (start code) segmentsAll applies it to prototypes, (start code) segments, and lines prefixed with >, |, or :.  The default is Code.

-do
--documented-only

Tells Natural Docs to only include what you explicitly document in the output, and not to find undocumented classes, functions, and variables.  This option is only relevant if you have full language support.

-oft
--only-file-titles

Tells Natural Docs to only use the file name for its menu and page titles.  It won’t try to determine one from the contents of the file.

-nag
--no-auto-group

Tells Natural Docs to not automatically create group topics if you don’t add them yourself.

-q
--quiet

Suppresses all non-error output.

-?
-h
--help

Prints the syntax reference.

No Longer Supported:
These parameters were part of previous Natural Docs releases, but are no longer supported.
-ho
--headers-only

This used to check only the headers and not the source files in C and C++.  Edit Languages.txt instead and add the line “Ignore Extensions: c cpp cxx”.

-s Custom
--style Custom

This used to tell Natural Docs not to alter the CSS file in the output directory.  Copy your custom CSS file to your project directory and use it with -s instead.

-ag [level]
--auto-group [level]

This used to set the level of auto-grouping between Full, Basic, and None.  The algorithm was improved so there’s no need for separate levels anymore.  You can use -nag if you want to turn it off completely.

-cs [charset]
--charset [charset]
--character-set [charset]

This used to set the character set property of the generated HTML.  Natural Docs now always uses UTF-8.

Examples
NaturalDocs -i C:\My Project\Source
-            -o FramedHTML C:\My Project\Docs
-            -p C:\My Project\Natural Docs
-
-NaturalDocs -i /project/src1
-            -i /project/src2
-            -o HTML /project/doc
-            -p /project/nd
-            -s Small -t 3
Copyright © 2003-2010 Greg Valure
\ No newline at end of file diff --git a/vendor/naturaldocs/Help/styles.css b/vendor/naturaldocs/Help/styles.css deleted file mode 100644 index 905f0140a..000000000 --- a/vendor/naturaldocs/Help/styles.css +++ /dev/null @@ -1,292 +0,0 @@ - -body { - background: #FFFFFF; - margin: 18px 15px 25px 15px !important; - } - -body, -td, -li { - font: 9pt Verdana, sans-serif; - } -p, -td, -li { - line-height: 150%; - } - -p { - text-indent: 4ex; - margin: 0; - } - -td { - vertical-align: top; - } - -a:link, -a:visited { color: #900000; text-decoration: none } -a:hover { color: #900000; text-decoration: underline } -a:active { color: #FF0000; text-decoration: underline } - -.Opera wbr:after { - content: "\00200B"; - } - -.NoIndent p - { text-indent: 0; } - -img { - border: none; - } - -.First { - margin-top: 0 !important; - padding-top: 0 !important; - } -.Last { - margin-bottom: 0 !important; - padding-bottom: 0 !important; - } - -.PageTable { - max-width: 950px; - margin-left: auto; - margin-right: auto; - } - -.Header { - background-image: URL("images/header/background.png"); - background-color: #7070C0; - } -.SideMenuTop { - background: URL("images/header/overmenubg.png"); - } -.SideMenuBottom { - vertical-align: bottom; - } -.BodyTop { - background: URL("images/header/overbodybg.png"); - text-align: right; - } -.BodyBottom { - vertical-align: bottom; - text-align: right; - font: italic 8pt Georgia, serif; - color: #C0C0C0; - padding-right: 10px; - } - -.Body { - padding: 15px 20px 0 25px; - } - - - - -pre, code, .Example { - font: 10pt Courier New, Courier, monospace; - color: #606060; - } -a code { - color: #C06060; - } -.Example { - overflow: auto; - } - -.PageTitle { - font: bold italic 21pt Trebuchet MS, sans-serif; letter-spacing: .5ex; text-transform: uppercase; - margin-bottom: .5em } -.IE .PageTitle { - letter-spacing: 1.25ex; - } - - -.Topic { - margin-bottom: 2em } - - -.TopicTitle { - font: 18pt Georgia, serif; - border-width: 0 0 1px 0; border-style: solid; border-color: #C0C0C0; - margin-bottom: .5em - } -#SubscribeTopicTitle { - margin-bottom: 0; - } -.Subscribe { - font-size: 8pt; - margin-bottom: 2em; - color: #909090; - } - -.Subscribe a:link, -.Subscribe a:hover, -.Subscribe a:visited { - color: #909090 } - - -.SubTopic { - font-weight: bold; font-size: 10pt; - padding-top: 1.5em; padding-bottom: .5em; - } - -.MiniTopic { - font-weight: bold; - padding-top: 1em; padding-bottom: 0em; - } - - -.TOC { - text-align: center; - font: 8pt Verdana, sans-serif; - text-transform: uppercase; - background-color: #F8F8F8; - border-width: 1px; border-style: solid; border-color: #C0C0C0; - margin-bottom: 1.5em; - padding: 2px 0; - -moz-border-radius: 14px; - } - - .TOC a { - margin: 0 0.75ex; } - - .TOC a:link, - .TOC a:hover, - .TOC a:visited { - color: #404040 } - - -.Example { - background-color: #FDFDFD; - padding: 15px; - border: 1px solid #C0C0C0; - border-width: 1px 1px 1px 6px; - border-style: dashed dashed dashed solid; - color: #707070; - margin: 15px 5ex; - } - - -.LastUpdated { - font: italic 10pt Georgia, serif; - color: #A0A0A0; - margin: 1em 0; - } - - - -.FAQSummary { - margin-bottom: 3em; - } -.FAQSummaryGroup { - font: bold 12pt Georgia, serif; - margin: 1em 0 .25em 0; - } -.FAQGroup { - font: 18pt Georgia, serif; - border-bottom: 1px solid #C0C0C0; - margin-bottom: .5em; - margin-top: 1.5em; - } -.FAQSummaryEntry:link, -.FAQSummaryEntry:visited, -.FAQSummaryEntry:hover, -.FAQSummaryEntry:active { - } - -.FAQEntry { - margin-bottom: 3em; - } -.FAQEntryTitle { - font: bold 12pt Georgia, serif; - margin-bottom: .5em; - } -.FAQEntry .SubTopic { - font: italic 9pt Verdana, sans-serif; - } - - - -.SideMenu { - width: 175px; /* 195 minus padding */ - text-align: center; - padding-top: 15px; - background-color: #F0F0F0; - } -.SideMenuBottom { - background-color: #F0F0F0; - } -.SideMenuBottomRight { - text-align: right; - } - -.SideMenuSection { - margin-bottom: 3em; - } - -.SideMenuTitle { - padding-bottom: 3px; - border-bottom: 1px solid #D0D0D0; - } - -.SideMenuBody { - padding-top: 1em; - background: URL("images/menu/background.png") repeat-x; - } - -.SideMenuEntry { - font: 8pt Verdana, sans-serif; - margin: 0 10px 1em 10px; - display: block; - } - -a.SideMenuEntry:link, -a.SideMenuEntry:visited { - color: #000000; - padding: 1px 10px 2px 9px; - } -a.SideMenuEntry:hover, -a.SideMenuEntry:active, -#SelectedSideMenuEntry { - border-style: solid; - border-width: 1px 2px 2px 1px; - padding: 0 8px; - text-decoration: none; - -moz-border-radius: 10px; - } -a.SideMenuEntry:hover, -a.SideMenuEntry:active { - color: #000000; - border-color: #C8C8C8; - background-color: #F8F8F8; - } -#SelectedSideMenuEntry { - color: #000000; - border-color: #606060; - background-color: #FFFFFF; - } - -.SideMenuSourceForge { - padding-top: 2.5em; - } - - - -/* Needed by the release notes for 1.3 */ - -.ExPrototype { - font: 10pt Courier New, Courier, monospace; - padding: 5px 3ex; - background-color: #F4F4F4; - border: 1px solid #D0D0D0; - margin: 1em 0; - } -.ExPrototype td { - font: 10pt Courier New, Courier, monospace; - } -.ExPrototype .Fade { - color: #8F8F8F; - } - diff --git a/vendor/naturaldocs/Help/styles.html b/vendor/naturaldocs/Help/styles.html deleted file mode 100644 index 808341d1c..000000000 --- a/vendor/naturaldocs/Help/styles.html +++ /dev/null @@ -1,52 +0,0 @@ - - -CSS Styles - Natural Docs - - - -
Natural Docs
CSS Styles
Default Styles

These are the styles that come with Natural Docs.  They all follow the same color scheme and general layout; the choices are more so that you can choose the style of text you want.

You choose which style you want for your project by adding “-s [style name]” to the command line.

DefaultThis is the default style that Natural Docs uses.  Most of the text is 10pt Verdana.
SmallSmaller fonts than Default with most of the text using 8pt Verdana.  Some people like the small fonts because you can fit more on the screen at once.  However, some people hate them and find them hard to read.
RomanSerif fonts with most of the text using 12pt Roman.  Some people prefer Roman fonts, usually those that have decent anti-aliasing displays like Mac OS X or Windows XP with ClearType.
Customizing

There are two ways to customize the CSS files.  One is to build your own file from scratch, and the other is to make a touch-up file that gets applied after one of the default styles.  Either way you want to create your own CSS file in your project directory (the one you use with -p) or if you plan on sharing it between many projects, in Natural Docs’ Styles directory.

To use a custom file, no matter where you put it, you just use it with -s without the CSS extension.  So if you made Red.css, you use “-s Red”.  If you made a touch-up file instead, you use it after one of the default styles, such as with “-s Default Red”.  If you’re so inclined, you can string as many touch-up files together as you want or use one of your own as a base.

The CSS Guide documents the page structure and CSS styles of Natural Docs’ output.  Always remember to check its revisions section every time you upgrade Natural Docs because it may change between releases.

Common Customizations
Web-Style Paragraphs

Natural Docs defaults to print-style paragraphs like the one you are reading.  Each one is indented and there are no blank lines between them.  To switch to web-style paragraphs, which have blank lines and no indents, add this to your custom CSS file:

p {
-   text-indent: 0;
-   margin-bottom: 1em;
-   }
-
Prototype Colors

If you’ve added a custom topic type and have it finding prototypes for you, you may want to have them appear in a different color than the default black and white.  Add this to your custom CSS file:

.C[type] .Prototype {
-   background-color: [color];
-   border-color: [color];
-   }
-

Replace [type] with the name of your topic type, minus any symbols and spaces.  So if you added a type “Sound Effect”, you would apply the style to “.CSoundEffect .Prototype”.

Copyright © 2003-2010 Greg Valure
\ No newline at end of file diff --git a/vendor/naturaldocs/Help/troubleshooting.html b/vendor/naturaldocs/Help/troubleshooting.html deleted file mode 100644 index 3cc089e80..000000000 --- a/vendor/naturaldocs/Help/troubleshooting.html +++ /dev/null @@ -1,18 +0,0 @@ - - -Troubleshooting - Natural Docs - - - -
Natural Docs
Troubleshooting
Natural Docs Issues
I don’t get any documentation
Is it recognizing your source files?

If Natural Docs has never said “Parsing n files...” when you run it, or n was way too low a number, it is not finding your source files.

If it has, try this test.  Run Natural Docs once.  Edit one of your source files and save it.  Run Natural Docs again.  If it doesn’t say “Parsing 1 file...” it is not recognizing your file.

No, it’s not recognizing them

The most likely scenario is that Natural Docs doesn’t associate the file extension you’re using with your programming language.  Open Languages.txt in Natural Docs’ Config directory and find your language.  Underneath it you should see a line that says something like “Extensions: c cpp cxx h hpp hxx”.  Add the file extensions you use and try again.

If you use extensionless or .cgi files, do the same thing but instead look for a line that says something like “Shebang Strings: tclsh wish expect”.  If it is not there, you may need to add it yourself.  Edit it to include whatever appears in your shebang (#!) line that would say this file belongs to your language.

Otherwise just make sure you included the directory or one of its parents with -i on the command line.

Yes, it’s recognizing them

First note that unless you have full language support, Natural Docs will only include what you write for it.  It will not be able to scan your code and pick out all the classes and functions on its own.

If the problem is with text files, the most likely scenario is that you’re not including topic lines.  Like in comments, only things that appear under “keyword: name” lines count as Natural Docs content.

If it’s still not working, note that Natural Docs can only read ASCII or UTF-8 encoded files that use Windows (CR+LF) or Unix (LF) line endings.  If you use UTF-16 encoded files and/or classic Mac (CR) line endings you need to convert the files.  These are due to limitations in Perl.  Natural Docs 2.0 won’t have these problems.

Some of my topics don’t show up
  • Check the list of keywords to see if the one you’re using is there and you spelled it correctly.  Note that the web page only has the default set of keywords.  You may need to check Topics.txt in Natural Docs’ Config directory and your project directory if you’ve edited them
  • If the topics appear in code, make sure that the comments are alone on a line.  You cannot put Natural Docs content on the same line as code.  This includes having anything appear after a closing block comment symbol.
  • Make sure that if you have more than one topic in a comment, there is a blank line above the topic line.
  • If you have text boxes or lines, make sure they are completely unbroken.  You can also try removing them completely.
  • If the topics appear in a text file, make sure you included topic lines.  Like in comments, only things that appear after “keyword: name” lines count as Natural Docs content.  You could just add a Title: line to the top of the file to fix this.
Some of my topics aren’t formatting correctly
  • Headings must have a blank line above them.
  • Lines directly after bullet or definition lines are part of the previous bullet or definition, even if it’s not indented.  Skip a line first to do something else
  • If you’re getting symbols scattered throughout your text, make sure any text boxes or lines are completely unbroken.  You can also try removing them altogether.
  • If your example source code is getting mangled, remember to use the example code syntax.
  • If a line’s becoming a heading but shouldn’t, either get rid of the colon at the end or break it into two lines so the colon appears on the second line
  • If a line’s becoming a definition but shouldn’t, either get rid of the space-dash-space (use two dashes or remove one of the spaces) or break it into two lines so that the space-dash-space is on the second line.

I realize the last two aren’t great.  If you have any ideas as to how to reliably detect these kinds of false positives, e-mail me.

I’m not getting prototypes
  • The topic must appear directly above the thing it’s documenting.
  • Topics documented in lists will not get prototypes, even if the list break apart in the output.
  • The topic name must be present in the prototype somewhere.  Make sure the topic title has the same case as in the prototype and that it’s not misspelled.  This applies even if your language isn’t case sensitive.
  • If you’re documenting something with a new topic type you added to Topics.txt, you must also edit Languages.txt to tell it how to detect prototypes for that type.
My links aren’t working

If your links appear in the output as “<text>” instead of being converted to links, do the following:

  • Make sure the target appears in the output.  The easiest way is to see if it appears in the Everything index.
  • Make sure the link is spelled correctly and has the same case as what you’re linking to.  This applies even if your language isn’t case sensitive.
  • If the topic your link appears in and the link target are not in the same class (or are not both global) make sure you include the class in the link with class.target, class::target, or class->target.  You can check which classes topics appear in with the Everything index.  If your topics are appearing in the wrong classes, fix the documentation remembering the topic scoping rules.
Windows Issues
I get the message “Bad command or file name” or “perl is not recognized”

What’s happening is that NaturalDocs.bat can’t find Perl.  You need Perl installed to run Natural Docs, so if you haven’t done so already, you can download and install ActiveState’s ActivePerl for free.

If you already have Perl, it’s bin directory is either not in your path or the path isn’t being used by whatever you’re running it from, which happens on some IDEs.  Edit NaturalDocs.bat and on the line that says “perl NaturalDocs %NaturalDocsParams%”, change perl to be the full path to perl.exe, such as “C:\perl\bin\perl.exe”.  You need to include the quotes if there are spaces in the path.

I get the message “Can’t open perl script NaturalDocs”

What’s happening is that Perl can’t find the Natural Docs script file.  This happens when the working directory or “start in” folder isn’t the directory Natural Docs was installed to.  If changing that doesn’t work, or if you don’t have the option to set that, edit NaturalDocs.bat and find the line that says “perl NaturalDocs %NaturalDocsParams%”.  Change NaturalDocs to include the full path Natural Docs was installed to, such as “C:\Program Files\Natural Docs\NaturalDocs”.  You need to include the quotes if there are spaces in the path.

Copyright © 2003-2010 Greg Valure
\ No newline at end of file diff --git a/vendor/naturaldocs/Info/CSSGuide.txt b/vendor/naturaldocs/Info/CSSGuide.txt deleted file mode 100644 index 2496b0bfc..000000000 --- a/vendor/naturaldocs/Info/CSSGuide.txt +++ /dev/null @@ -1,947 +0,0 @@ - - Architecture: CSS Structure -_______________________________________________________________________________ - -It's important to understand the internal HTML file structure and styles in order to design your own CSS style for Natural Docs. If -you're content with the default styles, there's no need to read this document. - -Topic: Diagram Conventions - - The diagrams are designed for clarity. In the actual HTML, you'd obviously see "
" - instead of "
". - - - A tag with just a style, for example "CTitle", means an unspecified element with that class. Style with .CTitle. - - A tag that includes a #, for example "#Menu", means an unspecified element with that ID. Style with #Menu. - - A tag that includes a HTML element as well, for example "table CDescriptionList", means it will always be that element. You - can style with either .CDescriptionList or table.CDescriptionList. - - A tag that has multiple classes or has an "and" in it, for example "CType and CTopic", means that both styles will apply to the - same element. You can style it with .CType.CTopic, noting that the space between them must be omitted. - - A tag that has an "or" in it, for example "#Content or #Index", is just shorthand for either of those elements. The diagram - applies to both of them but only one will actually appear at a time in the output. - - A tag or style with a question mark means that tag or style will only be there in certain situations. - - -Topic: Page Structure -_______________________________________________________________________________ - - The body tag is used to distinguish between the types of pages. - - Unframed Content/Index Page: - - (start diagram) - - - [browser styles] - - <#Content or #Index> - Content or Index - - - <#Menu> - Menu - - - <#Footer> - Footer - - - [/browser styles] - - - (end diagram) - - - Unframed Search Results Popup Page: - - (start diagram) - - - [browser styles] - - <#Index> - Index - - - [browser styles] - - - (end diagram) - - - Framed Menu Page: - - (start diagram) - - - [browser styles] - - <#Menu> - Menu - - - <#Footer> - Footer - - - [browser styles] - - - (end diagram) - - - Framed Content/Index/SearchResults Page: - - (start diagram) - - - [browser styles] - - <#Content or #Index> - Content or Index - - - [browser styles] - - - (end diagram) - - -Styles: Page Styles - - ContentPage - An unframed content page. - IndexPage - An unframed index page. - PopupSearchResultsPage - A search results page for use in a popup iframe. - - FramedContentPage - A framed content page. - FramedIndexPage - A framed index page. - FramedSearchResultsPage - A framed search results page. - - #Footer - The page footer. Will be in a framed menu page or on its own in a non-framed page. - - See Also: - - - <#Content> - - <#Menu> - - <#Index> - - <#Footer> - - - - -Styles: Browser Styles -_______________________________________________________________________________ - - - Natural Docs pages include JavaScript to detect which browser the user is running and apply styles so that you can work - around browser quirks right in the CSS file. - - The browser type and version styles will be applied immediately after the body tag. However, neither are guaranteed to be - there; the user may have JavaScript turned off or be using a browser that isn't detected. These styles should only be used to - correct minor flaws and should not be heavily relied on. - - > - > ? - > ? - > - > Page Content - > - > ? - > ? - > - - For example, if a 's style is giving you problems in Internet Explorer 6, override it with .IE6 .CTopic. If a 's - style gives you a problem in Opera 7 but only in frames, override it with .Framed.Opera7 .MTitle. - - Browser Types: - - If the browser is not one of the types below, neither this nor the browser version will be present. There's the possibility that - some obscure browser will appear as one of the others by spoofing, but the most prominent of these, Opera, Konqueror, and - Safari, are taken care of. - - IE - Internet Explorer - Firefox - Firefox and anything else based on the Gecko rendering engine. - Opera - Opera - Safari - Safari - Konqueror - Konqueror and anything else based on the KHTML rendering engine except Safari. - - Browser Versions: - - If the browser is not one of the versions below, this style will not be present. The browser type still may be. - - IE6 - Internet Explorer 6.x. - IE7 - Internet Explorer 7.x. - - Firefox1 - Firefox 1.0.x and anything else based on Gecko 1.7.x. - Firefox15 - Firefox 1.5.x and anything else based on Gecko 1.8.0.x. - Firefox2 - Firefox 2.0.x and anything else based on Gecko 1.8.1.x. - - Opera7 - Opera 7.x. - Opera8 - Opera 8.x. - Opera9 - Opera 9.x. - - Safari2 - Safari 2.x. - Safari3 - Safari 3.x. - - Notes: - - Why not apply them to the body tag itself? The JavaScript is easy enough and everything supports multiple classes, right? - Because IE 6 doesn't support multiple selectors so I wouldn't be able to combine browser and page styles. - .Opera.ContentPage will apply to all ContentPages in IE because it treats it as if only the last class is there. - - - - -Topic: Content Structure -_______________________________________________________________________________ - - - All the topics of a given file is contained in a <#Content>. All other content styles are prefixed with a C. - - Surrounding each piece of content is a and its type; for example, CFunction for a function. Inside that are the - and if necessary, . Inside are analogues to all the top-level tags:

,

, etc. - - In addition to the top-level tags, you also have prototypes, class hierarchies, and summaries which are - described in their own sections. - - (start diagram) - - <#Content> - - - - - - Topic title - - - - - [Class Hierarchy] - - [Prototype] - - - Heading - - -

- Paragraph -

- -
-                        Code or text diagram
-                    
- -
    -
  • - Bullet item -
  • -
- - ? - Caption - ? - - - - text - - - - - - - -
- Entry - - Description -
- - [Summary] - - - - - - - - - (end diagram) - - Take advantange of the CSS inheritance model. For example, you can style all titles via .CTitle, and you can style - specific titles with .CType .CTitle. - - -Styles: Content Styles - - #Content - Parent element containing all topics. - - CTopic - An individual topic. - - CTitle - The title of a topic. - CBody - The body of a topic. May not exist. - CHeading - Surrounds a heading. - CImageCaption - Surrounds an image caption. - CImageLink - Surrounds a link to an image. - - CDescriptionList - A description list, which is the type of list you're reading right now. Is implemented with a table. - CDLEntry - A description list entry, which is the left side. - CDLDescription - A description list description, which is the right side. - - #MainTopic - The ID given to the main topic, which is the first in the file. It is applied to the . - - CType - A placeholder for all type-specific styles. The actual styles will be C followed by the alphanumeric-only topic type name. - So the CType of a "PL/SQL Function" topic will actually be CPLSQLFunction. - - - - -Topic: Menu Structure -_______________________________________________________________________________ - - - Everything is enclosed in a <#Menu>. All other menu styles are prefixed with an M. - - The title is an and will always be at the beginning of the menu if it exists. If a subtitle exists as well, it will appear - as an inside . Subtitles aren't allowed without titles. Most other entries in the menu are contained in - . Here's the diagram: - - (start diagram) - - <#Menu> - - - Menu title - - - Menu sub title - - - - - - - File - - - - - - File - - - - - - Text - - - - - - Link - - - - - - Group - - - (MEntries) - - - - - - <#MSearchPanel and MSearchPanelActive/Inactive> - - - - - - - (if in unframed HTML) - <#MSearchResultsWindow> - - - - - - - - (end) - - The or entry that's currently selected will have the <#MSelected> ID, so you can reference it in CSS via - .MFile#MSelected. - - The search panel is has its own ID, <#MSearchPanel>, but also has one of the classes or - depending on whether any of the controls are selected or the results window is open. - <#MSearchResultsWindow> is separate because it may be floating. - - -Styles: Menu Styles - - #Menu - Parent element containing the entire menu. - - MTitle - The title of the menu. - MSubTitle - The subtitle of the menu. Will appear within . - - MFile - A file entry. - MGroup - A group entry. - MGroupContent - A container for a content. - MText - A plain text entry. - MLink - An external link entry. - MIndex - An index entry. - - #MSelected - The ID of the currently selected or . - - MType - , , , , or . - - #MSearchPanel - Contains all the search controls. - MSearchPanelActive - Applied to <#MSearchPanel> when any of the controls are selected or the results window is open. - MSearchPanelInactive - Applied to <#MSearchPanel> when not in use. - - #MSearchField - The text input field of the search panel. - #MSearchType - The drop down type selector of the search panel. - #MSearchEverything - The <#MSearchType> option for the Everything index. - - #MSearchResultsWindow - Contains all the search results elements. - #MSearchResults - Contains the iframe that will hold the results. - #MSearchRseultsWindowClose - The link to manually close the search results window. - - - - -Topic: Class Hierarchy Structure -_______________________________________________________________________________ - - - Everything is contained in a single . Each entry is surrounded by its type, such as , and the - generic . Depending on the context, entries may be surrounded by one or more . - - (start diagram) - - - - ? - - - - - ? - Entry - - - - - - ? - - - - (end diagram) - - -Styles: Class Hierarchy Styles - - ClassHierarchy - The topmost style containing everything. - - CHEntry - A generic class entry. - - CHParent - The style for a parent class. - CHCurrent - The style for the current class, which is the one the hierarchy is generated for. - CHChild - The style for a child class. - CHChildNote - The style for when a child is added that just shows how many other children were omitted. - - CHIndent - A style used to indent a level. - - CHType - , , , or . - - - - -Topic: Summary Structure -_______________________________________________________________________________ - - - Everything is enclosed in a single . All the other summary styles are prefixed with an S. - - holds the actual word "Summary" and and hold the content. exists because different - browsers apply table padding attributes in different ways. exists as a class to separate the main table from any other - tables that may be necessary. Here's a diagram: - - > - > - > - > Title - > - > - > - > - > ... - >
- >
- > - >
- - On to the table content. - - > - > - > - > Entry - > - > - > - > - > Description - > - > - > - - exist to allow indenting. They're necessary because implementing it as nested tables, while structurally cleaner, - won't allow the desciptions to line up on the right throughout the entire summary. will be applied on almost every - other row to allow for tinting to improve readability. - - Use the power of CSS's inheritance rules to specify styles. For example, to set the style of a group entry, apply it to - .SGroup .SEntry. However, you could also apply a style to both the group's entry and description by applying the - style to .SGroup td. Or, you could apply a style to all the entries by applying it to .SEntry. And so on. - - -Styles: Summary Styles - - Summary - The topmost style containing the entire summary. - - STitle - Contains the summary title, which is the part that actually says "Summary". - - SBorder - Surrounds , since some browsers can't do table padding right. A hack, I know. - STable - The actual summary table. This class separates it from other layout tables that may appear. - - SMarked - A class applied to rows that should have a slightly different color than the rest of the rows to make them easier to - read. - - SEntry - The entry (left) side of the table. - SDescription - The description (right) side of the table. - - SIndent# - Surrounding entries and descriptions that are part of a group and need to be indented. Actual styles will be - SIndent1, SIndent2, etc. - - SType - A placeholder for all topic-specific styles. The actual styles will be S followed by the alphanumeric-only topic type name. - So the SType of a "PL/SQL Function" topic will actually be SPLSQLFunction. - - - - -Topic: Prototype Structure -_______________________________________________________________________________ - - - Everything is enclosed in a . All other styles are prefixed with a P. - - Parameter Type First Style: - - For prototypes such as - > void Function (unsigned int* a, int b = 0) - where the types come first. - - (start diagram) - - - - - - - - - - - - - - - - - - (repeated as necessary) - - - -
- "void Function (" - - "unsigned" - - "int" - - "*" - - "a", "b" - - "=" - - "0" - - ")" -
- - (end diagram) - - - Parameter Name First Style: - - For prototypes such as - > function Function (a, b: int; c: int := 0) - where the parameters come first. - - (start diagram) - - - - - - - - - - - - - - (repeated as necessary) - - - -
- "function Function (" - - "a,", "b:", "c:" - - "int" - - ":=" - - "0" - - ")" -
- - (end diagram) - - - Note that any section may not exist. For example, there will be no cells generated if none of the parameters - have it. - - -Styles: Prototype Styles - - Prototype - The style encompassing the entire prototype. - - PBeforeParameters - The part of the prototype that comes before the parameters. - PAfterParameters - The part of the prototype that comes after the parameters. - - PType - The parameter type. - PTypePrefix - The prefix of a parameter type. - PParameter - The parameter name. - PParameterPrefix - The prefix of a parameter name. - PDefaultValue - The default value expression for a parameter. - PDefaultValuePrefix - The prefix of the default value expression. - - - - -Topic: Link Structure -_______________________________________________________________________________ - - - All links to symbols have a type style prefixed with L. The only exceptions are summary entries; summary descriptions use - them as well. - - > - > Link - > - - You can use this to make links to different symbols appear in different styles. For example, making .LClass bold will make all - links to classes bold, except when appearing in summary entries. You can combine this with other styles to be even more - specific. For example, you can apply a style to function links appearing in summary descriptions with .SDescription .LFunction. - -Styles: Link Styles - - LType - A placeholder for all topic-specific styles. The actual styles will be L followed by the alphanumeric-only topic type name. - So the LType of a "PL/SQL Function" topic will actually be LPLSQLFunction. - - - -Topic: Index Structure -_______________________________________________________________________________ - - - Everything is enclosed in an <#Index>. Combine with and to distinguish between output formats. All - other index styles are prefixed with an I. - - (start diagram) - - <#Index> - - - Page Title - - - - A - B - C ... - - - - - - Heading (A, B, etc.) - - - - - - - ... - -
- Prefix, if any - - Entry -
- - - - (end diagram) - - Every index entry, including headings, are rows in a table. The first column of a non-heading are so that - the non-prefix portions align correctly. The other column are , of which there are multiple formats, described below. - - (start diagram) - - - Symbol - , - - Class - - - - Symbol - - - - Class - - ... - - - - Symbol - - - - Class - - - - File - - ... - - ... - - - (end diagram) - - Each part of the entry is surrounded by its type, which may or may not be a link. If an entry has more than one defining class - or file, they're broken out into . - - It's called instead of because class entries are . are only used when the symbol - has a class. If the symbol _is_ a class, the symbol is global. - - -Styles: Index Styles - - #Index - Parent element for the entire index. - - IPageTitle - The page title. - INavigationBar - The navigation bar. - - IHeading - An index heading, such as the letter for the group. - - IEntry - An entry in the index. - ISymbolPrefix - The stripped prefix of the entry. - ISymbol - The entry symbol. - IParent - The entry parent class. If the entry _is_ a class, this isn't defined because classes are global and don't have parent - classes. This is why it's called IParent instead of IClass; hopefully it's less confusing. - IFile - The file the entry is defined in. - - ISubIndex - The surrounding block if an entry needs to be broken out into a sub-index. - - #IFirstHeading - The ID of the first to appear in the file. - - #IFirstSymbolPrefix - The ID for the first to appear under an . - #ILastSymbolPrefix - The ID for the last to appear under an . - #IOnlySymbolPrefix - The ID if there is only one for an . - - - -Topic: Search Results Structure -_______________________________________________________________________________ - - - The search results use virtually the same structure and styles as the indexes, except that <#SearchResults> replaces - <#Index>, there's a new style, and there are a few additional blocks. - - Visibility: - - Visibility is *very* important to making the search work correctly. JavaScript will handle most of it, but your CSS needs to - abide by these rules. - - - sections are visible by default. - - sections are *not* visible by default. They must use display: none. - - should be display: none when under <#SearchResults>. - - -Styles: Search Results Styles - - #SearchResults - Parent element for the entire page. - SRStatus - Status message. Must be visible by default. - SRResult - A result. All you need to do for this class is set it to display: none. Nothing else should be set on it. - - - - -Topic: Tool Tip Structure -_______________________________________________________________________________ - - - Tool tips may appear anywhere in the page, mainly because it's assumed that they will use position: absolute and - visibility: hidden. - - The entire tool tip is found in a style, with a CType style inside it. CTypes are normally outside their elements, but - that would cause it to be partially visible in this case. We need to be the outermost style so its visibility and - position can be manipulated in JavaScript. - - Inside there's a and/or the description text. The description text has no special surrounding tags. - - > - > - > - > Prototype - > - > - > Summary text - > - > - -Styles: Tool Tip Styles - - CToolTip - Surrounds the entire tool tip. This *must* have position: absolute and visibility: hidden for the tool tip mechanism - to work. - - See also . - - -Styles: Miscellaneous Styles - - blockquote - This HTML element should surround anything that needs to be scrolled if it's too wide, like prototypes and text - diagrams. It's not a style because this makes it much easier to do the JavaScript necessary to get this working - in IE. - - -Group: History - -Topic: Revisions -_______________________________________________________________________________ - - - How the page structure has changed throughout the various releases. - - 1.4: - - - Replaced UnframedPage with and . - - Added <#Menu>, <#Content>, <#Footer>, and <#Index>. They were previously shown in the diagrams as classes but did - not actually appear in the generated output. - - Removed MenuSection, ContentSection, and IndexSection. Use things like ".ContentPage #Menu" instead. - - Removed tables from the unframed . Use CSS to position the elements instead. - - <#MainTopic> is applied to instead of . - - IE4, IE5, Opera5, Opera6, Netscape, and Netscape4 browser styles have been removed. , , - and have been added. Gecko has been replaced by , , , and . - KHTML has been replaced by , , , and . - - Removed redundant CParagraph, CCode, and CBulletList classes. Use with p, pre, and ul instead. - - Added and . - - Added <#MSearchPanel>, <#MSearchResultsWindow>, and all related styles. - - Added , , and . - - Removed SEntrySize. Apply the width to and instead. - - , , and were moved from the td and divs into the tr. - - Removed HB style. Now using wbr tag. - - 1.33: - - - Added . - - 1.32: - - - now surround elements that should scroll if they're too wide for the page. - - 1.3: - - - Removed CPrototype. See the replacement and . - - Removed SInGroup, SInClass, and SInSection in favor of more general . - - , , and are now completely determined by configuration files. - - , , and no longer have separate list types. A CFunctionList is now just a CFunction. - - Indexes are now done with tables. - - ISection was removed. - - are only used for the entry cell, not for each entry in an . - - Added , related IDs, and <#IFirstHeading>. - - Merged and into the same element. Must now be styled with .CType.CTopic (no space) while all - sub-elements will still be .CType .CElement (with space.) - - 1.21: - - - Added and TOPIC_PROPERTY_LIST styles, so they get corresponding , , and - . - - 1.2: - - - Added since 1.2 added class hierarchies. - - 1.16: - - - Changed the first topic from having a CMain type to having a normal type with a <#MainTopic> ID. - - 1.1: - - - Added . - - Renamed HiddenBreak to . - - Added , TOPIC_CONSTANT_LIST, , and TOPIC_TYPE_LIST types, so they get - corresponding , , and . - - 1.0: - - - The tags now appear arround the tags instead of vice versa. - - Added a tag to surround non- elements. - - now appears in tr's instead of td's, where it belonged in the first place. - - 0.95: - - - Added . - - Redid , replacing generic styles like Menu with page type styles like UnframedPage/MenuSection and - FramedMenuPage. - - 0.91: - - - Added and link styles, since 0.91 added URL and e-mail links. - - Added style, which is better than floating on its own. - - 0.9: - - - Added , since 0.9 added indexes. - diff --git a/vendor/naturaldocs/Info/File Parsing.txt b/vendor/naturaldocs/Info/File Parsing.txt deleted file mode 100644 index 10bd0e91b..000000000 --- a/vendor/naturaldocs/Info/File Parsing.txt +++ /dev/null @@ -1,83 +0,0 @@ - - Architecture: File Parsing - -#################################################################################### - - This is the architecture and code path for general file parsing. We pick it up at Parse()> because we're not interested in how the files are gathered and their languages determined for the purposes of this document. We are just interested in the process each individual file goes through when it's decided that it should be parsed. - - - - Stage: Preparation and Differentiation - _______________________________________________________________________________________________________ - - Parse()> can be called from one of two places, ParseForInformation()> and ParseForBuild()>, which correspond to the parsing and building phases of Natural Docs. There is no noteworthy work done in either of them before they call Parse(). - - - Stage: Basic File Processing - _______________________________________________________________________________________________________ - - The nitty-gritty file handling is no longer done in itself due to the introduction of full language support in 1.3, as it required two completely different code paths for full and basic language support. Instead it's handled in NaturalDocs::Languages::Base->ParseFile(), which is really a virtual function that leads to ParseFile()> for basic language support or a version appearing in a package derived from for full language support. - - The mechinations of how these functions work is for another document, but their responsibility is to feed all comments Natural Docs should be interested in back to the parser via OnComment()>. - - - Stage: Comment Processing - _______________________________________________________________________________________________________ - - OnComment()> receives the comment sans comment symbols, since that's language specific. All comment symbols are replaced by spaces in the text instead of removed so any indentation is properly preserved. Also passed is whether it's a JavaDoc styled comment, as that varies by language as well. - - OnComment() runs what it receives through CleanComment()> which normalizes the text by removing comment boxes and horizontal lines, expanding tabs, etc. - - - Stage: Comment Type Determination - _______________________________________________________________________________________________________ - - OnComment() sends the comment to IsMine()> to test if it's definitely Natural Docs content, such as by starting with a recognized header line. If so, it sends it to ParseComment()>. - - If not, OnComment() sends the comment to IsMine()> to test if it's definitely JavaDoc content, such as by having JavaDoc tags. If so, it sends it to ParseComment()>. - - If not, the content is ambiguous. If it's a JavaDoc-styled comment it goes to ParseComment()> to be treated as a headerless Natural Docs comment. It is ignored otherwise, which lets normal comments slip through. Note that it's only ambiguous if neither parser claims it; there's no test to see if they both do. Instead Natural Docs always wins. - - We will not go into the JavaDoc code path for the purposes of this document. It simply converts the JavaDoc comment into as best it can, which will never be perfectly, and adds a to the list for that file. Each of those ParsedTopics will be headerless as indicated by having an undefined Title()>. - - - Stage: Native Comment Parsing - _______________________________________________________________________________________________________ - - At this point, parsing is handed off to ParseComment()>. It searches for header lines within the comment and divides the content into individual topics. It also detects (start code) and (end) sections so that anything that would normally be interpreted as a header line can appear there without breaking the topic. - - The content between the header lines is sent to FormatBody()> which handles all the block level formatting such as paragraphs, bullet lists, and code sections. That function in turn calls RichFormatTextBlock()> on certain snippets of the text to handle all inline formatting, such as bold, underline, and links, both explicit and automatic. - - ParseComment()> then has the body in so it makes a to add to the list. It keeps track of the scoping via topic scoping, regardless of whether we're using full or basic language support. Headerless topics are given normal scope regardless of whether they might be classes or other scoped types. - - - Group: Post Processing - _______________________________________________________________________________________________________ - - After all the comments have been parsed into ParsedTopics and execution has been returned to Parse()>, it's time for some after the fact cleanup. Some things are done like breaking topic lists, determining the menu title, and adding automatic group headings that we won't get into here. There are two processes that are very relevant though. - - - Stage: Repairing Packages - _______________________________________________________________________________________________________ - - If the file we parsed had full language support, the parser would have done more than just generate various OnComment() calls. It would also return a scope record, as represented by objects, and a second set of ParsedTopics it extracted purely from the code, which we'll refer to as autotopics. The scope record shows, purely from the source, what scope each line of code appears in. This is then combined with the topic scoping to update ParsedTopics that come from the comments in the function RepairPackages()>. - - If a comment topic changes the scope, that's honored until the next autotopic or scope change from the code. This allows someone to document a class that doesn't appear in the code purely with topic scoping without throwing off anything else. Any other comment topics have their scope changed to the current scope no matter how it's arrived at. This allows someone to manually document a function without manually documenting the class and still have it appear under that class. The scope record will change the scope to part of that class even if topic scoping did not. Essentially the previous topic scoping is thrown out, which I guess is something that can be improved. - - None of this affects the autotopics, as they are known to have the correct scoping since they are gleaned from the code with a dedicated parser. Wouldn't there be duplication of manually documented code elements, which would appear both in the autotopics and in the comment topics? Yes. That brings us to our next stage, which is... - - - Stage: Merging Auto Topics - _______________________________________________________________________________________________________ - - As mentioned above, ParseFile() also returns a set of ParsedTopics gleaned from the code called autotopics. The function MergeAutoTopics()> merges this list with the comment topics. - - The list is basically merged by line number. Since named topics should appear directly above the thing that they're documenting, topics are tested that way and combined into one if they match. The description and title of the comment topic is merged with the prototype of the autotopic. JavaDoc styled comments are also merged in this function, as they should appear directly above the code element they're documenting. Any headerless topics that don't, either by appearing past the last autotopic or above another comment topic, are discarded. - - - Stage: Conclusion - _______________________________________________________________________________________________________ - - Thus ends all processing by Parse()>. The file is now a single list of with all the body content in . If we were using ParseForBuild()>, that's pretty much it and it's ready to be converted into the output format. If we were using ParseForInformation()> though, the resulting file is scanned for all relevant information to feed into other packages such as . - - Note that no prototype processing was done in this process, only the possible tranferring of prototypes from one ParsedTopic to another when merging autotopics with comment topics. Obtaining prototypes and formatting them is handled by and derived packages. diff --git a/vendor/naturaldocs/Info/HTMLTestCases.pm b/vendor/naturaldocs/Info/HTMLTestCases.pm deleted file mode 100644 index ea434a4a6..000000000 --- a/vendor/naturaldocs/Info/HTMLTestCases.pm +++ /dev/null @@ -1,270 +0,0 @@ -############################################################################### -# -# File: Browser Testing -# -############################################################################### -# -# This file tests Natural Docs' generated output. Particularly useful when testing various browsers. -# -############################################################################### - -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL) -# Refer to License.txt for the complete details - -use strict; -use integer; - - -# -# About: Browsers -# -# The specific browser versions tested are below. Everything is tested on Windows Vista unless otherwise noted. -# -# Firefox 2.0.0.10 - 2.0 released October 2006. -# Firefox 1.5.0.8 - 1.5 released Novemer 2005. -# Firefox 1.0.8 - 1.0 released November 2004. Not critical to support. -# -# IE 7.0 - 7.0 released October 2006. -# IE 6.0 - 6.0 released August 2001. Tested on Windows XP SP2 via Virtual PC. -# -# Safari 3.0.4 - 3.0 released June 2007. Tested Windows version. -# Safari 2.0.4 - 2.0 released April 2005. Tested on Mac OS X 10.4 Tiger. -# -# Opera 9.02 - 9.0 released June 2006. -# Opera 8.54 - 8.5 released September 2005. -# Opera 8.02 - 8.0 released April 2005. -# Opera 7.51 - 7.5 released around August 2004 I think. Not critical to support. -# Opera 7.02 - 7.0 released January 2003. Not critical to support. -# -# Konqueror 3.5.5 - Tested on openSUSE 10.2 via VMware Player. -# - - -############################################################################### -# Group: Search - -# -# Topic: Unframed HTML Search -# -# Tests: -# -# - Make sure the search box appears and disappears correctly on hover. -# - Type to bring up results. Type further to narrow them. Narrow until there's no results. -# - Backspace to bring the results back. Backspacing to empty closes the results. -# - Type to bring up results with a different first letter. (Tests iframe content switch.) -# - Type *Z* to bring up empty page when there's nothing with that first letter. (Tests generic no results page.) -# - Type *Name* in Everything search to test expanding and collapsing, especially between two that differ only by case. -# - Change filter to *Functions* to test changing filter while results are open. Change to *Types* to switch to one with -# no results. -# - Test Close button on results. Should deactivate panel as well. -# - Clicking away should deactivate panel if the box is empty, not have an effect if there are results open. -# - Text should always change back to "Search" when deactivating. -# -# Results: -# -# Firefox 2.0 - OK -# Firefox 1.5 - OK -# Firefox 1.0 - OK -# -# IE 7.0 - OK -# IE 6.0 - Functionally OK. Search panel doesn't activate on hover. Works fine when clicked. -# -# Safari 3.0 - OK -# Safari 2.0 - *Broken.* Results panel doesn't show up. Border around deactivated search box. -# -# Opera 9.0 - OK -# Opera 8.5 - OK -# Opera 8.0 - OK -# Opera 7.5 - Functionally OK. Search panel has sunken border when deactivated, minor pixel shifting. -# Opera 7.0 - *Broken.* Completely. -# -# Konqueror 3.5 - *Broken.* Results panel doesn't show up. Seems to fail on "resultsFrame = window.frames.MSearchResults;" -# - -# -# Topic: Framed HTML Search -# -# Tests: -# -# - Make sure the search box appears and disappears correctly on hover. -# - Type to bring up results on right. Type further to narrow them. Narrow until there's no results. -# - Backspace to bring the results back. -# - Type to bring up results with a different first letter. (Tests frame content switch.) -# - Type *Z* to bring up empty page when there's nothing with that first letter. (Tests generic no results page.) -# - Type *Name* in Everything search to see that there's no collapsing in this mode. -# - Change filter to *Functions* to test changing filter while results are open. Change to *Types* to switch to one with -# no results. -# - Clicking away should deactivate panel. -# - Clicking a result should deactivate panel and show up in correct frame. -# - Text should always change back to "Search" when deactivating. -# -# Results: -# -# Firefox 2.0 - OK -# Firefox 1.5 - OK -# Firefox 1.0 - OK -# -# IE 7.0 - OK -# IE 6.0 - Functionally OK. Search panel doesn't activate on hover, is a little wide. Works fine when clicked. -# -# Safari 3.0 - OK -# Safari 2.0 - Functionally OK. Has a sunken border around the deactivated seach field. -# -# Opera 9.0 - OK -# Opera 8.5 - OK -# Opera 8.0 - OK -# Opera 7.5 - Functionally OK. Search panel has sunken border when deactivated, minor pixel shifting. -# Opera 7.0 - *Broken.* -# -# Konqueror 3.5 - Functionally OK. Panel doesn't reset and deactivate when clicking a result link. -# - - -############################################################################### -# Group: Other - -# -# Topic: Images -# -# Tests: -# -# - Here is an embedded image on its own line. -# -# (see images/logo.png) -# -# - Here is a reference in the middle of a sentence, in the middle of a bullet list: (see images/logo.png) It should have been -# converted to a link with the image appearing below the bullet list and the file name used as a caption. Make sure the -# caption positions correctly. -# - Here's a link to a non-existent image, which should appear literally: (see images/doesntexist.jpg) -# - Here is an embedded image that doesn't exist on it's own line. -# -# (see images/doesntexist.png) -# -# - Here is a link using the "(see)" syntax which shouldn't be interpreted as an image link because it doesn't end with an -# acceptable extension. Also, links should still resolve because of that. (see ) -# -# Results: -# -# Firefox 2.0 - OK -# Firefox 1.5 - OK -# Firefox 1.0 - OK -# -# IE 7.0 - OK -# IE 6.0 - OK -# -# Safari 3.0 - OK -# Safari 2.0 - OK -# -# Opera 9.0 - OK -# Opera 8.5 - OK -# Opera 8.0 - OK -# Opera 7.5 - OK -# Opera 7.0 - OK -# -# Konqueror 3.5 - OK - - -# -# Topic: Prototypes and Tooltips -# -# Hover over ParseComment()> and IsMine()> -# -# Tests: -# -# - A tooltip should appear about a second after you hover over the link above. -# - It should go away when you move the cursor away. -# - It shoud be positioned directly underneath with a slight gap. -# - The prototype should be formatted cleanly with each parameter on its own line and aligned in columns. -# - The asterisk should be in a separate column. -# - Test it with the link too close to the edge of the window so the pop-up has to shift left to fit. -# -# Results: -# -# Firefox 2.0 - OK -# Firefox 1.5 - OK -# Firefox 1.0 - OK -# -# IE 7.0 - OK -# IE 6.0 - OK -# -# Safari 3.0 - OK -# Safari 2.0 - OK -# -# Opera 9.0 - OK. Has its own tooltips turned on by default which can cover it up though. -# Opera 8.5 - OK. Has its own tooltips turned on by default which can cover it up though. -# Opera 8.0 - OK. Has its own tooltips turned on by default which can cover it up though. -# Opera 7.5 - OK. Has its own tooltips turned on by default which can cover it up though. -# Opera 7.0 - *Broken.* Usually works, if the window is too narrow may collapse completely. -# -# Konqueror 3.5 - OK -# - - -# -# Topic: Long code block scrolling -# -# Go to . -# -# Tests: -# -# - Shrink the browser window so that a line extends past the end of it. Only the line should have a scrollbar, not the -# entire page. -# - Expand the browser window. The scrollbar should disappear. -# -# Results: -# -# Firefox 2.0 - OK -# Firefox 1.5 - OK -# Firefox 1.0 - OK -# -# IE 7.0 - OK -# IE 6.0 - OK -# -# Safari 3.0 - OK -# Safari 2.0 - OK -# -# Opera 9.0 - OK -# Opera 8.5 - OK -# Opera 8.0 - OK -# Opera 7.5 - OK -# Opera 7.0 - OK -# -# Konqueror 3.5 - OK -# - - -# -# Topic: Menu and Class Hierarchies -# -# Go to . -# -# Tests: -# -# - Class hierarchy should look okay. -# - Make sure the menu hierarchy opens up on its own when the page is loaded. -# - You should be able to click on groups to open and close them. -# -# Results: -# -# Firefox 2.0 - OK -# Firefox 1.5 - OK -# Firefox 1.0 - OK -# -# IE 7.0 - OK -# IE 6.0 - OK -# -# Safari 3.0 - OK -# Safari 2.0 - OK -# -# Opera 9.0 - OK -# Opera 8.5 - OK -# Opera 8.0 - OK -# Opera 7.5 - OK -# Opera 7.0 - OK -# -# Konqueror 3.5 - OK -# - - -1; diff --git a/vendor/naturaldocs/Info/Languages.txt b/vendor/naturaldocs/Info/Languages.txt deleted file mode 100644 index c564eb582..000000000 --- a/vendor/naturaldocs/Info/Languages.txt +++ /dev/null @@ -1,107 +0,0 @@ - - Title: Language Notes -_______________________________________________________________________________ - - This is more for my personal reference than anything else. - - - ___________________________________________________________________________ - - Topic: Prototype Parameter Styles - ___________________________________________________________________________ - - Parameters via Commas, Typed via Spaces: - - > FunctionName ( type indentifier, type identifier = value, modifier type identifier ) - > FunctionName ( indentifier, identifier = value ) - - The general idea is that parameters are separated by commas. Identifiers cannot contain spaces. Types and modifiers, - if available, are separated from the identifiers with spaces. There may be an equals sign to set the default value. - - So parsing means splitting by commas, stripping everything past an equals sign for the default value, stripping everything - after the last space for the identifier, and the rest is the type. If there are no internal spaces after the default value is - stripped, it's all identifier. - - Note that internal parenthesis, brackets, braces, and angle brackets should be parsed out. They may be present in default - values or types and any commas and equal signs in them should not be included. - - Applies to C++, Java, C#, JavaScript, Python, PHP, Ruby. - - Applies to Perl as well, even though it doesn't have any real parameter declaration structure. Just adding it with comments - is fine. - - Parameters via Semicolons and Commas, Typed via Colons: - - > FunctionName ( identifier: type; identifier, identifier: type; identifier: type := value ) - - Parameters via semicolons, types via colons. However, there can be more than one parameter per type via commas. - Default values via colon-equals. - - Applies to Pascal, Ada. - - - SQL: - - > FunctionName ( identifier type, identifier modifier type, identifier type := value ) - - Parameters separated by commas. Identifiers come before the types and are separated by a space. Default values are - specified with colon-equals. - - > FunctionName @identifier type, @dentifier modifier type, @identifier type = value - - Microsoft's SQL uses equals instead of colon-equals, doesn't need parenthesis, and starts its parameter names with an @ - symbol. - - - Visual Basic: - - > FunctionName ( modifiers identifier as type, identifier = value ) - - Parameters separated by commas. Default values via equals. However, any number of modifiers may appear before the - identifier. Those modifiers are ByVal, ByRef, Optional, and ParamArray. - - - Tcl: - - > FunctionName { identifier identifier { whatever } } { code } - - Identifiers are specified in the first set of braces and have no commas. However, they can be broken out into sub-braces. - - - ___________________________________________________________________________ - - Topic: Syntax References - ___________________________________________________________________________ - - C++ - http://www.csci.csusb.edu/dick/c++std/syntax.html - - C# - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csspec/html/CSharpSpecStart.asp. Open in IE. - - Java - http://cui.unige.ch/db-research/Enseignement/analyseinfo/ - Ada - http://cui.unige.ch/db-research/Enseignement/analyseinfo/ - - SQL - http://cui.unige.ch/db-research/Enseignement/analyseinfo/, - , or - (open in IE). - - JavaScript - http://academ.hvcc.edu/~kantopet/javascript/index.php - - Python - http://www.python.org/doc/2.3.4/ref/ref.html - - PHP - http://www.php.net/manual/en/langref.php - - Visual Basic - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbls7/html/vbspecstart.asp. Open in IE. - - Pascal - . Open in IE. - - Ruby - http://www.rubycentral.com/book/ - - ActionScript 2 - - ActionScript 3 - - E2X - http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-357.pdf - - R - Somewhere on http://www.r-project.org. - - ColdFusion - - - Eiffel - http://www.gobosoft.com/eiffel/syntax/ diff --git a/vendor/naturaldocs/Info/NDMarkup.txt b/vendor/naturaldocs/Info/NDMarkup.txt deleted file mode 100644 index 23051722e..000000000 --- a/vendor/naturaldocs/Info/NDMarkup.txt +++ /dev/null @@ -1,92 +0,0 @@ - - Architecture: NDMarkup -_______________________________________________________________________________ - -A markup format used by the parser, both internally and in objects. Text formatted in -NDMarkup will only have the tags documented below. - - -About: Top-Level Tags - - All content will be surrounded by one of the top-level tags. These tags will not appear within each other. - -

- Surrounds a paragraph. Paragraph breaks will replace double line breaks, and single line breaks will - be removed completely. - - - Surrounds code or text diagrams that should appear literally in the output. The type can - be code, text, or anonymous, in which case it's not specified whether it's code or text. - - - Surrounds a heading. - -
    - Surrounds a bulleted (unordered) list. -
    - Surrounds a description list, which is what you are reading. - - - An inline image. Target contains the image target, and original contains the - original text in case it doesn't resolve. - - -About: List Item Tags - - These tags will only appear within their respective lists. - -
  • - Surrounds a bulleted list item. - - Surrounds a description list entry, which is the left side. It will always be followed by a description list - description. - - Surrounds a description list symbol. This is the same as a description list entry, except that the content - is also a referenceable symbol. This occurs when inside a list topic. This tag will always - be followed by a description list description. -
    - Surrounds a description list description, which is the right side. It will always be preceded by a description - list entry or symbol. - -About: Text Tags - - These tags will only appear in paragraphs, headings, or description list descriptions. - - - Bold - - Italics - - Underline - - - Surrounds a potential link to a symbol; potential because the target is not guaranteed to - exist. This tag merely designates an attempted link. Target is what is attempting to be - linked to, name is the text that should appear for a successful link, and original is the - original text in case the link doesn't resolve. - - - An external link. There's no need for an original attribute because it will always be - turned into an actual link. - - A link to an e-mail address. - - - An image link. Target contains the image target, and original contains the original - text in case it doesn't resolve. - - -About: Amp Chars - - These are the only amp chars supported, and will appear everywhere. Every other character will appear as is. - - & - The ampersand &. - " - The double quote ". - < - The less than sign <. - > - The greater than sign >. - -About: Tabs - - NDMarkup will not contain tab characters, only spaces. Any tab characters appearing in the source files will be - expanded/replaced as necessary. - - -About: General Tag Properties - - Since the tags are generated, they will always have the following properties, which will make pattern matching much - easier. - - - Tags and amp chars will always be in all lowercase. - - Properties will appear exactly as documented here. They will be in all lowercase, in the documented order, and will have no - extraneous whitespace. Anything appearing in the properties will have amp chars. - - All code is valid, meaning tags will always be closed,
  • s will only appear within
      s, etc. - - So, for example, you can match description list entries with /(.+?)<\/de>/ and $1 will be the text. No surprises or - gotchas. No need for sophisticated parsing routines. - - Remember that for symbol definitions, the text should appear as is, but internally (such as for the anchor) they need to - be passed through Defines()> so that the output file is just as tolerant as - . diff --git a/vendor/naturaldocs/Info/Symbol Management.txt b/vendor/naturaldocs/Info/Symbol Management.txt deleted file mode 100644 index fb2bad233..000000000 --- a/vendor/naturaldocs/Info/Symbol Management.txt +++ /dev/null @@ -1,59 +0,0 @@ - - Architecture: Symbol Management - -#################################################################################### - - This is the architecture and code path for symbol management. This is almost exclusively managed by , but it's complicated enough that I want a plain-English walk through of the code paths anyway. - - An important thing to remember is that each section below is simplified initially and then expanded upon in later sections as more facets of the code are introduced. You will not get the whole story of what a function does by reading just one section. - - - - Topic: Symbol Storage - _______________________________________________________________________________________________________ - - Symbols are indexed primarily by their , which is the normalized, pre-parsed series of identifiers that make it up. A symbol can have any number of definitions, including none, but can only have one definition per file. If a symbol is defined more than once in a file, only the first definition is counted. Stored for each definition is the , summary, and prototype. - - Each symbol that has a definition has one designated as the global definition. This is the one linked to by other files, unless that file happens to have its own definition which then takes precedence. Which definition is chosen is rather arbitrary at this point; probably the first one that got defined. Similarly, if the global definition is deleted, which one is chosen to replace it is completely arbitrary. - - Each symbol also stores a list of references to it. Note that references can be interpreted as multiple symbols, and each of those symbols will store a link back to the reference. In other words, every reference a symbol stores is one that _can_ be interpreted as that symbol, but that is not necessarily the interpretation the reference actually uses. A reference could have a better interpretation it uses instead. - - For example, suppose there are two functions, MyFunction() and MyClass.MyFunction(). The reference text "MyFunction()" appearing in MyClass can be interpreted as either MyClass.MyFunction(), or if that doesn't exist, the global MyFunction(). Both the symbols for MyFunction() and MyClass.MyFunction() will store that it's referenced by the link, even though the class scoped one serves as the actual definition. - - This is also the reason a symbol can exist that has no definitions: it has references. We want symbols to be created in the table for each reference interpretation, even if it doesn't exist. These are called potential symbols. The reason is so we know whether a new symbol definition fulfills an existing reference, since it may be a better interpretation for the reference than what is currently used. - - - - Topic: Reference Storage - _______________________________________________________________________________________________________ - - References are indexed primarily by their , which is actually an elaborate data structure packed into a string. It includes a of the text that appears in the link and a bunch of other data that determines the rules by which the link can be resolved. For example, it includes the scope it appears in and any "using" statements in effect, which are alternate possible scopes. It includes the type of link it is (text links, the ones you explicitly put in comments, aren't the only kind) and resolving flags which encode the language-specific rules of non-text links. But the bottom line is the encodes everything that influences how it may be resolved, so if two links come up with the same rules, they're considered two definitions of the same reference. This is the understanding of the word "reference" that will used in this document. - - Like symbols, each reference stores a list of definitions. However, it only stores the name as all the other relevant information is encoded in the itself. Unlike a symbol, which can be linked to the same no matter what kind of definitions it has, references that are in any way different might be interpreted differently and so need their own distinct entries in the symbol table. - - References also store a list of interpretations. Every possible interpretation of the reference is stored and given a numeric score. The higher the score, the better it suits the reference. In the MyFunction() example from before, MyClass.MyFunction() would have a higher score than just MyFunction() because the local scope should win. Each interpretation has a unique score, there are no duplicates. - - So the symbol and reference data structures are complimentary. Each symbol has a list of every reference that might be interpreted as it, and every reference has a list of each symbol that it could be interpreted as. Again, objects are created for potential symbols (those with references but no definitions) so that this structure always remains intact. - - The interpretation with the highest score which actually exists is deemed the current interpretation of the reference. Unlike symbols where the next global definition is arbitrary, the succession of reference interpretations is very controlled and predictable. - - - Topic: Change Detection - _______________________________________________________________________________________________________ - - Change management is handled a couple of ways. First, there is a secondary file index in that stores which symbols and references are stored in each file. It doesn't have any information other than a list of and since they can be used in the main structures to look up the details. If a file is deleted, the symbol table can then prune any definitions that should no longer be in the table. - - Another way deals with how the information parsing stage works. Files parsed for information just have their symbols and references added to the table regardless of whether this was the first time it was ever parsed or if it had been parsed before. If it had been parsed before, all the information from the previous parse should be in the symbol table and file indexes already. If a new symbol or reference is defined, that's fine, it's added to the table normally. However, if a symbol is redefined it's ignored because only the first definition matters. Also, this won't detect things that disappear. - - Enter watched files. tells to designate a file as watched before it starts parsing it, and then says to analyze the changes when it's done. The watched file is a second index of all the symbols and references that were defined since the watch started, including the specific details on the symbol definitions. When the analysis is done, it compares the list of symbols and references to the one in the main file index. Any that appear in the main file index but not the watched one are deleted because they didn't show up the second time around. Any symbol definitions that are different in the watched file than the main file are changed to the former, since the first definition that appeared the second time around was different than the original. - - - Topic: Change Management - _______________________________________________________________________________________________________ - - When a symbol's global definition changes, either because it switches to another file or because the details of the current file's definition changed (prototype, summary, etc.) it goes through all the references that can be interpreted as that symbol, finds the ones that use it as their current definition, and marks all the files that define them for rebuilding. The links in their output files have to be changed to the new definition or at least have their tooltips updated. - - When a symbol's last definition is deleted, it goes through all the references that can be interpreted as that symbol, finds the ones that use it as their current definition, and has them reinterpreted to the definition with the next highest score. The files that define them are also marked for rebuilding. - - When a potential symbol's first definition is found, it goes through all the references that can be interpreted as it and sees if it can serve as a higher scored interpretation than the current one. If so, the interpretations are changed and all the files that define them are marked for rebuilding. - diff --git a/vendor/naturaldocs/Info/images/Logo.png b/vendor/naturaldocs/Info/images/Logo.png deleted file mode 100644 index 87395ec5e..000000000 Binary files a/vendor/naturaldocs/Info/images/Logo.png and /dev/null differ diff --git a/vendor/naturaldocs/JavaScript/GooglePrettify.js b/vendor/naturaldocs/JavaScript/GooglePrettify.js deleted file mode 100644 index fda4bf1ed..000000000 --- a/vendor/naturaldocs/JavaScript/GooglePrettify.js +++ /dev/null @@ -1,1526 +0,0 @@ - -// This code comes from the December 2009 release of Google Prettify, which is Copyright © 2006 Google Inc. -// Minor modifications are marked with "ND Change" comments. -// As part of Natural Docs, this code is licensed under version 3 of the GNU Affero General Public License (AGPL.) -// However, it may also be obtained separately under version 2.0 of the Apache License. -// Refer to License.txt for the complete details - - -// Main code -// ____________________________________________________________________________ - -// Copyright (C) 2006 Google Inc. -// -// Licensed 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. - - -/** - * @fileoverview - * some functions for browser-side pretty printing of code contained in html. - *

      - * - * For a fairly comprehensive set of languages see the - * README - * file that came with this source. At a minimum, the lexer should work on a - * number of languages including C and friends, Java, Python, Bash, SQL, HTML, - * XML, CSS, Javascript, and Makefiles. It works passably on Ruby, PHP and Awk - * and a subset of Perl, but, because of commenting conventions, doesn't work on - * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class. - *

      - * Usage:

        - *
      1. include this source file in an html page via - * {@code } - *
      2. define style rules. See the example page for examples. - *
      3. mark the {@code
        } and {@code } tags in your source with
        - *    {@code class=prettyprint.}
        - *    You can also use the (html deprecated) {@code } tag, but the pretty
        - *    printer needs to do more substantial DOM manipulations to support that, so
        - *    some css styles may not be preserved.
        - * </ol>
        - * That's it.  I wanted to keep the API as simple as possible, so there's no
        - * need to specify which language the code is in, but if you wish, you can add
        - * another class to the {@code <pre>} or {@code <code>} element to specify the
        - * language, as in {@code <pre class="prettyprint lang-java">}.  Any class that
        - * starts with "lang-" followed by a file extension, specifies the file type.
        - * See the "lang-*.js" files in this directory for code that implements
        - * per-language file handlers.
        - * <p>
        - * Change log:<br>
        - * cbeust, 2006/08/22
        - * <blockquote>
        - *   Java annotations (start with "@") are now captured as literals ("lit")
        - * </blockquote>
        - * @requires console
        - * @overrides window
        - */
        -
        -// JSLint declarations
        -/*global console, document, navigator, setTimeout, window */
        -
        -/**
        - * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
        - * UI events.
        - * If set to {@code false}, {@code prettyPrint()} is synchronous.
        - */
        -window['PR_SHOULD_USE_CONTINUATION'] = true;
        -
        -/** the number of characters between tab columns */
        -window['PR_TAB_WIDTH'] = 8;
        -
        -/** Walks the DOM returning a properly escaped version of innerHTML.
        -  * @param {Node} node
        -  * @param {Array.<string>} out output buffer that receives chunks of HTML.
        -  */
        -window['PR_normalizedHtml']
        -
        -/** Contains functions for creating and registering new language handlers.
        -  * @type {Object}
        -  */
        -  = window['PR']
        -
        -/** Pretty print a chunk of code.
        -  *
        -  * @param {string} sourceCodeHtml code as html
        -  * @return {string} code as html, but prettier
        -  */
        -  = window['prettyPrintOne']
        -/** Find all the {@code <pre>} and {@code <code>} tags in the DOM with
        -  * {@code class=prettyprint} and prettify them.
        -  * @param {Function?} opt_whenDone if specified, called when the last entry
        -  *     has been finished.
        -  */
        -  = window['prettyPrint'] = void 0;
        -
        -/** browser detection. @extern @returns false if not IE, otherwise the major version. */
        -window['_pr_isIE6'] = function () {
        -  var ieVersion = navigator && navigator.userAgent &&
        -      navigator.userAgent.match(/\bMSIE ([678])\./);
        -  ieVersion = ieVersion ? +ieVersion[1] : false;
        -  window['_pr_isIE6'] = function () { return ieVersion; };
        -  return ieVersion;
        -};
        -
        -
        -(function () {
        -  // Keyword lists for various languages.
        -  var FLOW_CONTROL_KEYWORDS =
        -      "break continue do else for if return while ";
        -  var C_KEYWORDS = FLOW_CONTROL_KEYWORDS + "auto case char const default " +
        -      "double enum extern float goto int long register short signed sizeof " +
        -      "static struct switch typedef union unsigned void volatile ";
        -  var COMMON_KEYWORDS = C_KEYWORDS + "catch class delete false import " +
        -      "new operator private protected public this throw true try typeof ";
        -  var CPP_KEYWORDS = COMMON_KEYWORDS + "alignof align_union asm axiom bool " +
        -      "concept concept_map const_cast constexpr decltype " +
        -      "dynamic_cast explicit export friend inline late_check " +
        -      "mutable namespace nullptr reinterpret_cast static_assert static_cast " +
        -      "template typeid typename using virtual wchar_t where ";
        -  var JAVA_KEYWORDS = COMMON_KEYWORDS +
        -      "abstract boolean byte extends final finally implements import " +
        -      "instanceof null native package strictfp super synchronized throws " +
        -      "transient ";
        -  var CSHARP_KEYWORDS = JAVA_KEYWORDS +
        -      "as base by checked decimal delegate descending event " +
        -      "fixed foreach from group implicit in interface internal into is lock " +
        -      "object out override orderby params partial readonly ref sbyte sealed " +
        -      "stackalloc string select uint ulong unchecked unsafe ushort var ";
        -  var JSCRIPT_KEYWORDS = COMMON_KEYWORDS +
        -      "debugger eval export function get null set undefined var with " +
        -      "Infinity NaN ";
        -  var PERL_KEYWORDS = "caller delete die do dump elsif eval exit foreach for " +
        -      "goto if import last local my next no our print package redo require " +
        -      "sub undef unless until use wantarray while BEGIN END ";
        -  var PYTHON_KEYWORDS = FLOW_CONTROL_KEYWORDS + "and as assert class def del " +
        -      "elif except exec finally from global import in is lambda " +
        -      "nonlocal not or pass print raise try with yield " +
        -      "False True None ";
        -  var RUBY_KEYWORDS = FLOW_CONTROL_KEYWORDS + "alias and begin case class def" +
        -      " defined elsif end ensure false in module next nil not or redo rescue " +
        -      "retry self super then true undef unless until when yield BEGIN END ";
        -  var SH_KEYWORDS = FLOW_CONTROL_KEYWORDS + "case done elif esac eval fi " +
        -      "function in local set then until ";
        -  var ALL_KEYWORDS = (
        -      CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS +
        -      PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS);
        -
        -  // token style names.  correspond to css classes
        -  /** token style for a string literal */
        -  var PR_STRING = 'str';
        -  /** token style for a keyword */
        -  var PR_KEYWORD = 'kwd';
        -  /** token style for a comment */
        -  var PR_COMMENT = 'com';
        -  /** token style for a type */
        -  var PR_TYPE = 'typ';
        -  /** token style for a literal value.  e.g. 1, null, true. */
        -  var PR_LITERAL = 'lit';
        -  /** token style for a punctuation string. */
        -  var PR_PUNCTUATION = 'pun';
        -  /** token style for a punctuation string. */
        -  var PR_PLAIN = 'pln';
        -
        -  /** token style for an sgml tag. */
        -  var PR_TAG = 'tag';
        -  /** token style for a markup declaration such as a DOCTYPE. */
        -  var PR_DECLARATION = 'dec';
        -  /** token style for embedded source. */
        -  var PR_SOURCE = 'src';
        -  /** token style for an sgml attribute name. */
        -  var PR_ATTRIB_NAME = 'atn';
        -  /** token style for an sgml attribute value. */
        -  var PR_ATTRIB_VALUE = 'atv';
        -
        -  /**
        -   * A class that indicates a section of markup that is not code, e.g. to allow
        -   * embedding of line numbers within code listings.
        -   */
        -  var PR_NOCODE = 'nocode';
        -
        -  /** A set of tokens that can precede a regular expression literal in
        -    * javascript.
        -    * http://www.mozilla.org/js/language/js20/rationale/syntax.html has the full
        -    * list, but I've removed ones that might be problematic when seen in
        -    * languages that don't support regular expression literals.
        -    *
        -    * <p>Specifically, I've removed any keywords that can't precede a regexp
        -    * literal in a syntactically legal javascript program, and I've removed the
        -    * "in" keyword since it's not a keyword in many languages, and might be used
        -    * as a count of inches.
        -    *
        -    * <p>The link a above does not accurately describe EcmaScript rules since
        -    * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works
        -    * very well in practice.
        -    *
        -    * @private
        -    */
        -  var REGEXP_PRECEDER_PATTERN = function () {
        -      var preceders = [
        -          "!", "!=", "!==", "#", "%", "%=", "&", "&&", "&&=",
        -          "&=", "(", "*", "*=", /* "+", */ "+=", ",", /* "-", */ "-=",
        -          "->", /*".", "..", "...", handled below */ "/", "/=", ":", "::", ";",
        -          "<", "<<", "<<=", "<=", "=", "==", "===", ">",
        -          ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[",
        -          "^", "^=", "^^", "^^=", "{", "|", "|=", "||",
        -          "||=", "~" /* handles =~ and !~ */,
        -          "break", "case", "continue", "delete",
        -          "do", "else", "finally", "instanceof",
        -          "return", "throw", "try", "typeof"
        -          ];
        -      var pattern = '(?:^^|[+-]';
        -      for (var i = 0; i < preceders.length; ++i) {
        -        pattern += '|' + preceders[i].replace(/([^=<>:&a-z])/g, '\\$1');
        -      }
        -      pattern += ')\\s*';  // matches at end, and matches empty string
        -      return pattern;
        -      // CAVEAT: this does not properly handle the case where a regular
        -      // expression immediately follows another since a regular expression may
        -      // have flags for case-sensitivity and the like.  Having regexp tokens
        -      // adjacent is not valid in any language I'm aware of, so I'm punting.
        -      // TODO: maybe style special characters inside a regexp as punctuation.
        -    }();
        -
        -  // Define regexps here so that the interpreter doesn't have to create an
        -  // object each time the function containing them is called.
        -  // The language spec requires a new object created even if you don't access
        -  // the $1 members.
        -  var pr_amp = /&/g;
        -  var pr_lt = /</g;
        -  var pr_gt = />/g;
        -  var pr_quot = /\"/g;
        -  /** like textToHtml but escapes double quotes to be attribute safe. */
        -  function attribToHtml(str) {
        -    return str.replace(pr_amp, '&amp;')
        -        .replace(pr_lt, '&lt;')
        -        .replace(pr_gt, '&gt;')
        -        .replace(pr_quot, '&quot;');
        -  }
        -
        -  /** escapest html special characters to html. */
        -  function textToHtml(str) {
        -    return str.replace(pr_amp, '&amp;')
        -        .replace(pr_lt, '&lt;')
        -        .replace(pr_gt, '&gt;');
        -  }
        -
        -
        -  var pr_ltEnt = /&lt;/g;
        -  var pr_gtEnt = /&gt;/g;
        -  var pr_aposEnt = /&apos;/g;
        -  var pr_quotEnt = /&quot;/g;
        -  var pr_ampEnt = /&amp;/g;
        -  var pr_nbspEnt = /&nbsp;/g;
        -  /** unescapes html to plain text. */
        -  function htmlToText(html) {
        -    var pos = html.indexOf('&');
        -    if (pos < 0) { return html; }
        -    // Handle numeric entities specially.  We can't use functional substitution
        -    // since that doesn't work in older versions of Safari.
        -    // These should be rare since most browsers convert them to normal chars.
        -    for (--pos; (pos = html.indexOf('&#', pos + 1)) >= 0;) {
        -      var end = html.indexOf(';', pos);
        -      if (end >= 0) {
        -        var num = html.substring(pos + 3, end);
        -        var radix = 10;
        -        if (num && num.charAt(0) === 'x') {
        -          num = num.substring(1);
        -          radix = 16;
        -        }
        -        var codePoint = parseInt(num, radix);
        -        if (!isNaN(codePoint)) {
        -          html = (html.substring(0, pos) + String.fromCharCode(codePoint) +
        -                  html.substring(end + 1));
        -        }
        -      }
        -    }
        -
        -    return html.replace(pr_ltEnt, '<')
        -        .replace(pr_gtEnt, '>')
        -        .replace(pr_aposEnt, "'")
        -        .replace(pr_quotEnt, '"')
        -        .replace(pr_nbspEnt, ' ')
        -        .replace(pr_ampEnt, '&');
        -  }
        -
        -  /** is the given node's innerHTML normally unescaped? */
        -  function isRawContent(node) {
        -    return 'XMP' === node.tagName;
        -  }
        -
        -  var newlineRe = /[\r\n]/g;
        -  /**
        -   * Are newlines and adjacent spaces significant in the given node's innerHTML?
        -   */
        -  function isPreformatted(node, content) {
        -    // PRE means preformatted, and is a very common case, so don't create
        -    // unnecessary computed style objects.
        -    if ('PRE' === node.tagName) { return true; }
        -    if (!newlineRe.test(content)) { return true; }  // Don't care
        -    var whitespace = '';
        -    // For disconnected nodes, IE has no currentStyle.
        -    if (node.currentStyle) {
        -      whitespace = node.currentStyle.whiteSpace;
        -    } else if (window.getComputedStyle) {
        -      // Firefox makes a best guess if node is disconnected whereas Safari
        -      // returns the empty string.
        -      whitespace = window.getComputedStyle(node, null).whiteSpace;
        -    }
        -    return !whitespace || whitespace === 'pre';
        -  }
        -
        -  function normalizedHtml(node, out) {
        -    switch (node.nodeType) {
        -      case 1:  // an element
        -        var name = node.tagName.toLowerCase();
        -        out.push('<', name);
        -        for (var i = 0; i < node.attributes.length; ++i) {
        -          var attr = node.attributes[i];
        -          if (!attr.specified) { continue; }
        -          out.push(' ');
        -          normalizedHtml(attr, out);
        -        }
        -        out.push('>');
        -        for (var child = node.firstChild; child; child = child.nextSibling) {
        -          normalizedHtml(child, out);
        -        }
        -        if (node.firstChild || !/^(?:br|link|img)$/.test(name)) {
        -          out.push('<\/', name, '>');
        -        }
        -        break;
        -      case 2: // an attribute
        -        out.push(node.name.toLowerCase(), '="', attribToHtml(node.value), '"');
        -        break;
        -      case 3: case 4: // text
        -        out.push(textToHtml(node.nodeValue));
        -        break;
        -    }
        -  }
        -
        -  /**
        -   * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally
        -   * matches the union o the sets o strings matched d by the input RegExp.
        -   * Since it matches globally, if the input strings have a start-of-input
        -   * anchor (/^.../), it is ignored for the purposes of unioning.
        -   * @param {Array.<RegExp>} regexs non multiline, non-global regexs.
        -   * @return {RegExp} a global regex.
        -   */
        -  function combinePrefixPatterns(regexs) {
        -    var capturedGroupIndex = 0;
        -
        -    var needToFoldCase = false;
        -    var ignoreCase = false;
        -    for (var i = 0, n = regexs.length; i < n; ++i) {
        -      var regex = regexs[i];
        -      if (regex.ignoreCase) {
        -        ignoreCase = true;
        -      } else if (/[a-z]/i.test(regex.source.replace(
        -                     /\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, ''))) {
        -        needToFoldCase = true;
        -        ignoreCase = false;
        -        break;
        -      }
        -    }
        -
        -    function decodeEscape(charsetPart) {
        -      if (charsetPart.charAt(0) !== '\\') { return charsetPart.charCodeAt(0); }
        -      switch (charsetPart.charAt(1)) {
        -        case 'b': return 8;
        -        case 't': return 9;
        -        case 'n': return 0xa;
        -        case 'v': return 0xb;
        -        case 'f': return 0xc;
        -        case 'r': return 0xd;
        -        case 'u': case 'x':
        -          return parseInt(charsetPart.substring(2), 16)
        -              || charsetPart.charCodeAt(1);
        -        case '0': case '1': case '2': case '3': case '4':
        -        case '5': case '6': case '7':
        -          return parseInt(charsetPart.substring(1), 8);
        -        default: return charsetPart.charCodeAt(1);
        -      }
        -    }
        -
        -    function encodeEscape(charCode) {
        -      if (charCode < 0x20) {
        -        return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16);
        -      }
        -      var ch = String.fromCharCode(charCode);
        -      if (ch === '\\' || ch === '-' || ch === '[' || ch === ']') {
        -        ch = '\\' + ch;
        -      }
        -      return ch;
        -    }
        -
        -    function caseFoldCharset(charSet) {
        -      var charsetParts = charSet.substring(1, charSet.length - 1).match(
        -          new RegExp(
        -              '\\\\u[0-9A-Fa-f]{4}'
        -              + '|\\\\x[0-9A-Fa-f]{2}'
        -              + '|\\\\[0-3][0-7]{0,2}'
        -              + '|\\\\[0-7]{1,2}'
        -              + '|\\\\[\\s\\S]'
        -              + '|-'
        -              + '|[^-\\\\]',
        -              'g'));
        -      var groups = [];
        -      var ranges = [];
        -      var inverse = charsetParts[0] === '^';
        -      for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {
        -        var p = charsetParts[i];
        -        switch (p) {
        -          case '\\B': case '\\b':
        -          case '\\D': case '\\d':
        -          case '\\S': case '\\s':
        -          case '\\W': case '\\w':
        -            groups.push(p);
        -            continue;
        -        }
        -        var start = decodeEscape(p);
        -        var end;
        -        if (i + 2 < n && '-' === charsetParts[i + 1]) {
        -          end = decodeEscape(charsetParts[i + 2]);
        -          i += 2;
        -        } else {
        -          end = start;
        -        }
        -        ranges.push([start, end]);
        -        // If the range might intersect letters, then expand it.
        -        if (!(end < 65 || start > 122)) {
        -          if (!(end < 65 || start > 90)) {
        -            ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);
        -          }
        -          if (!(end < 97 || start > 122)) {
        -            ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);
        -          }
        -        }
        -      }
        -
        -      // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]
        -      // -> [[1, 12], [14, 14], [16, 17]]
        -      ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1]  - a[1]); });
        -      var consolidatedRanges = [];
        -      var lastRange = [NaN, NaN];
        -      for (var i = 0; i < ranges.length; ++i) {
        -        var range = ranges[i];
        -        if (range[0] <= lastRange[1] + 1) {
        -          lastRange[1] = Math.max(lastRange[1], range[1]);
        -        } else {
        -          consolidatedRanges.push(lastRange = range);
        -        }
        -      }
        -
        -      var out = ['['];
        -      if (inverse) { out.push('^'); }
        -      out.push.apply(out, groups);
        -      for (var i = 0; i < consolidatedRanges.length; ++i) {
        -        var range = consolidatedRanges[i];
        -        out.push(encodeEscape(range[0]));
        -        if (range[1] > range[0]) {
        -          if (range[1] + 1 > range[0]) { out.push('-'); }
        -          out.push(encodeEscape(range[1]));
        -        }
        -      }
        -      out.push(']');
        -      return out.join('');
        -    }
        -
        -    function allowAnywhereFoldCaseAndRenumberGroups(regex) {
        -      // Split into character sets, escape sequences, punctuation strings
        -      // like ('(', '(?:', ')', '^'), and runs of characters that do not
        -      // include any of the above.
        -      var parts = regex.source.match(
        -          new RegExp(
        -              '(?:'
        -              + '\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]'  // a character set
        -              + '|\\\\u[A-Fa-f0-9]{4}'  // a unicode escape
        -              + '|\\\\x[A-Fa-f0-9]{2}'  // a hex escape
        -              + '|\\\\[0-9]+'  // a back-reference or octal escape
        -              + '|\\\\[^ux0-9]'  // other escape sequence
        -              + '|\\(\\?[:!=]'  // start of a non-capturing group
        -              + '|[\\(\\)\\^]'  // start/emd of a group, or line start
        -              + '|[^\\x5B\\x5C\\(\\)\\^]+'  // run of other characters
        -              + ')',
        -              'g'));
        -      var n = parts.length;
        -
        -      // Maps captured group numbers to the number they will occupy in
        -      // the output or to -1 if that has not been determined, or to
        -      // undefined if they need not be capturing in the output.
        -      var capturedGroups = [];
        -
        -      // Walk over and identify back references to build the capturedGroups
        -      // mapping.
        -      for (var i = 0, groupIndex = 0; i < n; ++i) {
        -        var p = parts[i];
        -        if (p === '(') {
        -          // groups are 1-indexed, so max group index is count of '('
        -          ++groupIndex;
        -        } else if ('\\' === p.charAt(0)) {
        -          var decimalValue = +p.substring(1);
        -          if (decimalValue && decimalValue <= groupIndex) {
        -            capturedGroups[decimalValue] = -1;
        -          }
        -        }
        -      }
        -
        -      // Renumber groups and reduce capturing groups to non-capturing groups
        -      // where possible.
        -      for (var i = 1; i < capturedGroups.length; ++i) {
        -        if (-1 === capturedGroups[i]) {
        -          capturedGroups[i] = ++capturedGroupIndex;
        -        }
        -      }
        -      for (var i = 0, groupIndex = 0; i < n; ++i) {
        -        var p = parts[i];
        -        if (p === '(') {
        -          ++groupIndex;
        -          if (capturedGroups[groupIndex] === undefined) {
        -            parts[i] = '(?:';
        -          }
        -        } else if ('\\' === p.charAt(0)) {
        -          var decimalValue = +p.substring(1);
        -          if (decimalValue && decimalValue <= groupIndex) {
        -            parts[i] = '\\' + capturedGroups[groupIndex];
        -          }
        -        }
        -      }
        -
        -      // Remove any prefix anchors so that the output will match anywhere.
        -      // ^^ really does mean an anchored match though.
        -      for (var i = 0, groupIndex = 0; i < n; ++i) {
        -        if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }
        -      }
        -
        -      // Expand letters to groupts to handle mixing of case-sensitive and
        -      // case-insensitive patterns if necessary.
        -      if (regex.ignoreCase && needToFoldCase) {
        -        for (var i = 0; i < n; ++i) {
        -          var p = parts[i];
        -          var ch0 = p.charAt(0);
        -          if (p.length >= 2 && ch0 === '[') {
        -            parts[i] = caseFoldCharset(p);
        -          } else if (ch0 !== '\\') {
        -            // TODO: handle letters in numeric escapes.
        -            parts[i] = p.replace(
        -                /[a-zA-Z]/g,
        -                function (ch) {
        -                  var cc = ch.charCodeAt(0);
        -                  return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';
        -                });
        -          }
        -        }
        -      }
        -
        -      return parts.join('');
        -    }
        -
        -    var rewritten = [];
        -    for (var i = 0, n = regexs.length; i < n; ++i) {
        -      var regex = regexs[i];
        -      if (regex.global || regex.multiline) { throw new Error('' + regex); }
        -      rewritten.push(
        -          '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');
        -    }
        -
        -    return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');
        -  }
        -
        -  var PR_innerHtmlWorks = null;
        -  function getInnerHtml(node) {
        -    // inner html is hopelessly broken in Safari 2.0.4 when the content is
        -    // an html description of well formed XML and the containing tag is a PRE
        -    // tag, so we detect that case and emulate innerHTML.
        -    if (null === PR_innerHtmlWorks) {
        -      var testNode = document.createElement('PRE');
        -      testNode.appendChild(
        -          document.createTextNode('<!DOCTYPE foo PUBLIC "foo bar">\n<foo />'));
        -      PR_innerHtmlWorks = !/</.test(testNode.innerHTML);
        -    }
        -
        -    if (PR_innerHtmlWorks) {
        -      var content = node.innerHTML;
        -      // XMP tags contain unescaped entities so require special handling.
        -      if (isRawContent(node)) {
        -        content = textToHtml(content);
        -      } else if (!isPreformatted(node, content)) {
        -        content = content.replace(/(<br\s*\/?>)[\r\n]+/g, '$1')
        -            .replace(/(?:[\r\n]+[ \t]*)+/g, ' ');
        -      }
        -      return content;
        -    }
        -
        -    var out = [];
        -    for (var child = node.firstChild; child; child = child.nextSibling) {
        -      normalizedHtml(child, out);
        -    }
        -    return out.join('');
        -  }
        -
        -  /** returns a function that expand tabs to spaces.  This function can be fed
        -    * successive chunks of text, and will maintain its own internal state to
        -    * keep track of how tabs are expanded.
        -    * @return {function (string) : string} a function that takes
        -    *   plain text and return the text with tabs expanded.
        -    * @private
        -    */
        -  function makeTabExpander(tabWidth) {
        -    var SPACES = '                ';
        -    var charInLine = 0;
        -
        -    return function (plainText) {
        -      // walk over each character looking for tabs and newlines.
        -      // On tabs, expand them.  On newlines, reset charInLine.
        -      // Otherwise increment charInLine
        -      var out = null;
        -      var pos = 0;
        -      for (var i = 0, n = plainText.length; i < n; ++i) {
        -        var ch = plainText.charAt(i);
        -
        -        switch (ch) {
        -          case '\t':
        -            if (!out) { out = []; }
        -            out.push(plainText.substring(pos, i));
        -            // calculate how much space we need in front of this part
        -            // nSpaces is the amount of padding -- the number of spaces needed
        -            // to move us to the next column, where columns occur at factors of
        -            // tabWidth.
        -            var nSpaces = tabWidth - (charInLine % tabWidth);
        -            charInLine += nSpaces;
        -            for (; nSpaces >= 0; nSpaces -= SPACES.length) {
        -              out.push(SPACES.substring(0, nSpaces));
        -            }
        -            pos = i + 1;
        -            break;
        -          case '\n':
        -            charInLine = 0;
        -            break;
        -          default:
        -            ++charInLine;
        -        }
        -      }
        -      if (!out) { return plainText; }
        -      out.push(plainText.substring(pos));
        -      return out.join('');
        -    };
        -  }
        -
        -  var pr_chunkPattern = new RegExp(
        -      '[^<]+'  // A run of characters other than '<'
        -      + '|<\!--[\\s\\S]*?--\>'  // an HTML comment
        -      + '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>'  // a CDATA section
        -      // a probable tag that should not be highlighted
        -      + '|<\/?[a-zA-Z](?:[^>\"\']|\'[^\']*\'|\"[^\"]*\")*>'
        -      + '|<',  // A '<' that does not begin a larger chunk
        -      'g');
        -  var pr_commentPrefix = /^<\!--/;
        -  var pr_cdataPrefix = /^<!\[CDATA\[/;
        -  var pr_brPrefix = /^<br\b/i;
        -  var pr_tagNameRe = /^<(\/?)([a-zA-Z][a-zA-Z0-9]*)/;
        -
        -  /** split markup into chunks of html tags (style null) and
        -    * plain text (style {@link #PR_PLAIN}), converting tags which are
        -    * significant for tokenization (<br>) into their textual equivalent.
        -    *
        -    * @param {string} s html where whitespace is considered significant.
        -    * @return {Object} source code and extracted tags.
        -    * @private
        -    */
        -  function extractTags(s) {
        -    // since the pattern has the 'g' modifier and defines no capturing groups,
        -    // this will return a list of all chunks which we then classify and wrap as
        -    // PR_Tokens
        -    var matches = s.match(pr_chunkPattern);
        -    var sourceBuf = [];
        -    var sourceBufLen = 0;
        -    var extractedTags = [];
        -    if (matches) {
        -      for (var i = 0, n = matches.length; i < n; ++i) {
        -        var match = matches[i];
        -        if (match.length > 1 && match.charAt(0) === '<') {
        -          if (pr_commentPrefix.test(match)) { continue; }
        -          if (pr_cdataPrefix.test(match)) {
        -            // strip CDATA prefix and suffix.  Don't unescape since it's CDATA
        -            sourceBuf.push(match.substring(9, match.length - 3));
        -            sourceBufLen += match.length - 12;
        -          } else if (pr_brPrefix.test(match)) {
        -            // <br> tags are lexically significant so convert them to text.
        -            // This is undone later.
        -            sourceBuf.push('\n');
        -            ++sourceBufLen;
        -          } else {
        -            if (match.indexOf(PR_NOCODE) >= 0 && isNoCodeTag(match)) {
        -              // A <span class="nocode"> will start a section that should be
        -              // ignored.  Continue walking the list until we see a matching end
        -              // tag.
        -              var name = match.match(pr_tagNameRe)[2];
        -              var depth = 1;
        -              var j;
        -              end_tag_loop:
        -              for (j = i + 1; j < n; ++j) {
        -                var name2 = matches[j].match(pr_tagNameRe);
        -                if (name2 && name2[2] === name) {
        -                  if (name2[1] === '/') {
        -                    if (--depth === 0) { break end_tag_loop; }
        -                  } else {
        -                    ++depth;
        -                  }
        -                }
        -              }
        -              if (j < n) {
        -                extractedTags.push(
        -                    sourceBufLen, matches.slice(i, j + 1).join(''));
        -                i = j;
        -              } else {  // Ignore unclosed sections.
        -                extractedTags.push(sourceBufLen, match);
        -              }
        -            } else {
        -              extractedTags.push(sourceBufLen, match);
        -            }
        -          }
        -        } else {
        -          var literalText = htmlToText(match);
        -          sourceBuf.push(literalText);
        -          sourceBufLen += literalText.length;
        -        }
        -      }
        -    }
        -    return { source: sourceBuf.join(''), tags: extractedTags };
        -  }
        -
        -  /** True if the given tag contains a class attribute with the nocode class. */
        -  function isNoCodeTag(tag) {
        -    return !!tag
        -        // First canonicalize the representation of attributes
        -        .replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,
        -                 ' $1="$2$3$4"')
        -        // Then look for the attribute we want.
        -        .match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/);
        -  }
        -
        -  /**
        -   * Apply the given language handler to sourceCode and add the resulting
        -   * decorations to out.
        -   * @param {number} basePos the index of sourceCode within the chunk of source
        -   *    whose decorations are already present on out.
        -   */
        -  function appendDecorations(basePos, sourceCode, langHandler, out) {
        -    if (!sourceCode) { return; }
        -    var job = {
        -      source: sourceCode,
        -      basePos: basePos
        -    };
        -    langHandler(job);
        -    out.push.apply(out, job.decorations);
        -  }
        -
        -  /** Given triples of [style, pattern, context] returns a lexing function,
        -    * The lexing function interprets the patterns to find token boundaries and
        -    * returns a decoration list of the form
        -    * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
        -    * where index_n is an index into the sourceCode, and style_n is a style
        -    * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to
        -    * all characters in sourceCode[index_n-1:index_n].
        -    *
        -    * The stylePatterns is a list whose elements have the form
        -    * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].
        -    *
        -    * Style is a style constant like PR_PLAIN, or can be a string of the
        -    * form 'lang-FOO', where FOO is a language extension describing the
        -    * language of the portion of the token in $1 after pattern executes.
        -    * E.g., if style is 'lang-lisp', and group 1 contains the text
        -    * '(hello (world))', then that portion of the token will be passed to the
        -    * registered lisp handler for formatting.
        -    * The text before and after group 1 will be restyled using this decorator
        -    * so decorators should take care that this doesn't result in infinite
        -    * recursion.  For example, the HTML lexer rule for SCRIPT elements looks
        -    * something like ['lang-js', /<[s]cript>(.+?)<\/script>/].  This may match
        -    * '<script>foo()<\/script>', which would cause the current decorator to
        -    * be called with '<script>' which would not match the same rule since
        -    * group 1 must not be empty, so it would be instead styled as PR_TAG by
        -    * the generic tag rule.  The handler registered for the 'js' extension would
        -    * then be called with 'foo()', and finally, the current decorator would
        -    * be called with '<\/script>' which would not match the original rule and
        -    * so the generic tag rule would identify it as a tag.
        -    *
        -    * Pattern must only match prefixes, and if it matches a prefix, then that
        -    * match is considered a token with the same style.
        -    *
        -    * Context is applied to the last non-whitespace, non-comment token
        -    * recognized.
        -    *
        -    * Shortcut is an optional string of characters, any of which, if the first
        -    * character, gurantee that this pattern and only this pattern matches.
        -    *
        -    * @param {Array} shortcutStylePatterns patterns that always start with
        -    *   a known character.  Must have a shortcut string.
        -    * @param {Array} fallthroughStylePatterns patterns that will be tried in
        -    *   order if the shortcut ones fail.  May have shortcuts.
        -    *
        -    * @return {function (Object)} a
        -    *   function that takes source code and returns a list of decorations.
        -    */
        -  function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {
        -    var shortcuts = {};
        -    var tokenizer;
        -    (function () {
        -      var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);
        -      var allRegexs = [];
        -      var regexKeys = {};
        -      for (var i = 0, n = allPatterns.length; i < n; ++i) {
        -        var patternParts = allPatterns[i];
        -        var shortcutChars = patternParts[3];
        -        if (shortcutChars) {
        -          for (var c = shortcutChars.length; --c >= 0;) {
        -            shortcuts[shortcutChars.charAt(c)] = patternParts;
        -          }
        -        }
        -        var regex = patternParts[1];
        -        var k = '' + regex;
        -        if (!regexKeys.hasOwnProperty(k)) {
        -          allRegexs.push(regex);
        -          regexKeys[k] = null;
        -        }
        -      }
        -      allRegexs.push(/[\0-\uffff]/);
        -      tokenizer = combinePrefixPatterns(allRegexs);
        -    })();
        -
        -    var nPatterns = fallthroughStylePatterns.length;
        -    var notWs = /\S/;
        -
        -    /**
        -     * Lexes job.source and produces an output array job.decorations of style
        -     * classes preceded by the position at which they start in job.source in
        -     * order.
        -     *
        -     * @param {Object} job an object like {@code
        -     *    source: {string} sourceText plain text,
        -     *    basePos: {int} position of job.source in the larger chunk of
        -     *        sourceCode.
        -     * }
        -     */
        -    var decorate = function (job) {
        -      var sourceCode = job.source, basePos = job.basePos;
        -      /** Even entries are positions in source in ascending order.  Odd enties
        -        * are style markers (e.g., PR_COMMENT) that run from that position until
        -        * the end.
        -        * @type {Array.<number|string>}
        -        */
        -      var decorations = [basePos, PR_PLAIN];
        -      var pos = 0;  // index into sourceCode
        -      var tokens = sourceCode.match(tokenizer) || [];
        -      var styleCache = {};
        -
        -      for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {
        -        var token = tokens[ti];
        -        var style = styleCache[token];
        -        var match = void 0;
        -
        -        var isEmbedded;
        -        if (typeof style === 'string') {
        -          isEmbedded = false;
        -        } else {
        -          var patternParts = shortcuts[token.charAt(0)];
        -          if (patternParts) {
        -            match = token.match(patternParts[1]);
        -            style = patternParts[0];
        -          } else {
        -            for (var i = 0; i < nPatterns; ++i) {
        -              patternParts = fallthroughStylePatterns[i];
        -              match = token.match(patternParts[1]);
        -              if (match) {
        -                style = patternParts[0];
        -                break;
        -              }
        -            }
        -
        -            if (!match) {  // make sure that we make progress
        -              style = PR_PLAIN;
        -            }
        -          }
        -
        -          isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);
        -          if (isEmbedded && !(match && typeof match[1] === 'string')) {
        -            isEmbedded = false;
        -            style = PR_SOURCE;
        -          }
        -
        -          if (!isEmbedded) { styleCache[token] = style; }
        -        }
        -
        -        var tokenStart = pos;
        -        pos += token.length;
        -
        -        if (!isEmbedded) {
        -          decorations.push(basePos + tokenStart, style);
        -        } else {  // Treat group 1 as an embedded block of source code.
        -          var embeddedSource = match[1];
        -          var embeddedSourceStart = token.indexOf(embeddedSource);
        -          var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;
        -          if (match[2]) {
        -            // If embeddedSource can be blank, then it would match at the
        -            // beginning which would cause us to infinitely recurse on the
        -            // entire token, so we catch the right context in match[2].
        -            embeddedSourceEnd = token.length - match[2].length;
        -            embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;
        -          }
        -          var lang = style.substring(5);
        -          // Decorate the left of the embedded source
        -          appendDecorations(
        -              basePos + tokenStart,
        -              token.substring(0, embeddedSourceStart),
        -              decorate, decorations);
        -          // Decorate the embedded source
        -          appendDecorations(
        -              basePos + tokenStart + embeddedSourceStart,
        -              embeddedSource,
        -              langHandlerForExtension(lang, embeddedSource),
        -              decorations);
        -          // Decorate the right of the embedded section
        -          appendDecorations(
        -              basePos + tokenStart + embeddedSourceEnd,
        -              token.substring(embeddedSourceEnd),
        -              decorate, decorations);
        -        }
        -      }
        -      job.decorations = decorations;
        -    };
        -    return decorate;
        -  }
        -
        -  /** returns a function that produces a list of decorations from source text.
        -    *
        -    * This code treats ", ', and ` as string delimiters, and \ as a string
        -    * escape.  It does not recognize perl's qq() style strings.
        -    * It has no special handling for double delimiter escapes as in basic, or
        -    * the tripled delimiters used in python, but should work on those regardless
        -    * although in those cases a single string literal may be broken up into
        -    * multiple adjacent string literals.
        -    *
        -    * It recognizes C, C++, and shell style comments.
        -    *
        -    * @param {Object} options a set of optional parameters.
        -    * @return {function (Object)} a function that examines the source code
        -    *     in the input job and builds the decoration list.
        -    */
        -  function sourceDecorator(options) {
        -    var shortcutStylePatterns = [], fallthroughStylePatterns = [];
        -    if (options['tripleQuotedStrings']) {
        -      // '''multi-line-string''', 'single-line-string', and double-quoted
        -      shortcutStylePatterns.push(
        -          [PR_STRING,  /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
        -           null, '\'"']);
        -    } else if (options['multiLineStrings']) {
        -      // 'multi-line-string', "multi-line-string"
        -      shortcutStylePatterns.push(
        -          [PR_STRING,  /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,
        -           null, '\'"`']);
        -    } else {
        -      // 'single-line-string', "single-line-string"
        -      shortcutStylePatterns.push(
        -          [PR_STRING,
        -           /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,
        -           null, '"\'']);
        -    }
        -    if (options['verbatimStrings']) {
        -      // verbatim-string-literal production from the C# grammar.  See issue 93.
        -      fallthroughStylePatterns.push(
        -          [PR_STRING, /^@\"(?:[^\"]|\"\")*(?:\"|$)/, null]);
        -    }
        -    if (options['hashComments']) {
        -      if (options['cStyleComments']) {
        -        // Stop C preprocessor declarations at an unclosed open comment
        -        shortcutStylePatterns.push(
        -            [PR_COMMENT, /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,
        -             null, '#']);
        -        fallthroughStylePatterns.push(
        -            [PR_STRING,
        -             /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,
        -             null]);
        -      } else {
        -        shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']);
        -      }
        -    }
        -    if (options['cStyleComments']) {
        -      fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]);
        -      fallthroughStylePatterns.push(
        -          [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]);
        -    }
        -    if (options['regexLiterals']) {
        -      var REGEX_LITERAL = (
        -          // A regular expression literal starts with a slash that is
        -          // not followed by * or / so that it is not confused with
        -          // comments.
        -          '/(?=[^/*])'
        -          // and then contains any number of raw characters,
        -          + '(?:[^/\\x5B\\x5C]'
        -          // escape sequences (\x5C),
        -          +    '|\\x5C[\\s\\S]'
        -          // or non-nesting character sets (\x5B\x5D);
        -          +    '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+'
        -          // finally closed by a /.
        -          + '/');
        -      fallthroughStylePatterns.push(
        -          ['lang-regex',
        -           new RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')
        -           ]);
        -    }
        -
        -    var keywords = options['keywords'].replace(/^\s+|\s+$/g, '');
        -    if (keywords.length) {
        -      fallthroughStylePatterns.push(
        -          [PR_KEYWORD,
        -           new RegExp('^(?:' + keywords.replace(/\s+/g, '|') + ')\\b'), null]);
        -    }
        -
        -    shortcutStylePatterns.push([PR_PLAIN,       /^\s+/, null, ' \r\n\t\xA0']);
        -    fallthroughStylePatterns.push(
        -        // TODO(mikesamuel): recognize non-latin letters and numerals in idents
        -        [PR_LITERAL,     /^@[a-z_$][a-z_$@0-9]*/i, null],
        -        [PR_TYPE,        /^@?[A-Z]+[a-z][A-Za-z_$@0-9]*/, null],
        -        [PR_PLAIN,       /^[a-z_$][a-z_$@0-9]*/i, null],
        -        [PR_LITERAL,
        -         new RegExp(
        -             '^(?:'
        -             // A hex number
        -             + '0x[a-f0-9]+'
        -             // or an octal or decimal number,
        -             + '|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)'
        -             // possibly in scientific notation
        -             + '(?:e[+\\-]?\\d+)?'
        -             + ')'
        -             // with an optional modifier like UL for unsigned long
        -             + '[a-z]*', 'i'),
        -         null, '0123456789'],
        -        [PR_PUNCTUATION, /^.[^\s\w\.$@\'\"\`\/\#]*/, null]);
        -
        -    return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);
        -  }
        -
        -  var decorateSource = sourceDecorator({
        -        'keywords': ALL_KEYWORDS,
        -        'hashComments': true,
        -        'cStyleComments': true,
        -        'multiLineStrings': true,
        -        'regexLiterals': true
        -      });
        -
        -  /** Breaks {@code job.source} around style boundaries in
        -    * {@code job.decorations} while re-interleaving {@code job.extractedTags},
        -    * and leaves the result in {@code job.prettyPrintedHtml}.
        -    * @param {Object} job like {
        -    *    source: {string} source as plain text,
        -    *    extractedTags: {Array.<number|string>} extractedTags chunks of raw
        -    *                   html preceded by their position in {@code job.source}
        -    *                   in order
        -    *    decorations: {Array.<number|string} an array of style classes preceded
        -    *                 by the position at which they start in job.source in order
        -    * }
        -    * @private
        -    */
        -  function recombineTagsAndDecorations(job) {
        -    var sourceText = job.source;
        -    var extractedTags = job.extractedTags;
        -    var decorations = job.decorations;
        -
        -    var html = [];
        -    // index past the last char in sourceText written to html
        -    var outputIdx = 0;
        -
        -    var openDecoration = null;
        -    var currentDecoration = null;
        -    var tagPos = 0;  // index into extractedTags
        -    var decPos = 0;  // index into decorations
        -    var tabExpander = makeTabExpander(window['PR_TAB_WIDTH']);
        -
        -    var adjacentSpaceRe = /([\r\n ]) /g;
        -    var startOrSpaceRe = /(^| ) /gm;
        -    var newlineRe = /\r\n?|\n/g;
        -    var trailingSpaceRe = /[ \r\n]$/;
        -    var lastWasSpace = true;  // the last text chunk emitted ended with a space.
        -
        -    // A helper function that is responsible for opening sections of decoration
        -    // and outputing properly escaped chunks of source
        -    function emitTextUpTo(sourceIdx) {
        -      if (sourceIdx > outputIdx) {
        -        if (openDecoration && openDecoration !== currentDecoration) {
        -          // Close the current decoration
        -          html.push('</span>');
        -          openDecoration = null;
        -        }
        -        if (!openDecoration && currentDecoration) {
        -          openDecoration = currentDecoration;
        -          html.push('<span class="', openDecoration, '">');
        -        }
        -        // This interacts badly with some wikis which introduces paragraph tags
        -        // into pre blocks for some strange reason.
        -        // It's necessary for IE though which seems to lose the preformattedness
        -        // of <pre> tags when their innerHTML is assigned.
        -        // http://stud3.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
        -        // and it serves to undo the conversion of <br>s to newlines done in
        -        // chunkify.
        -        var htmlChunk = textToHtml(
        -            tabExpander(sourceText.substring(outputIdx, sourceIdx)))
        -            .replace(lastWasSpace
        -                     ? startOrSpaceRe
        -                     : adjacentSpaceRe, '$1&nbsp;');
        -        // Keep track of whether we need to escape space at the beginning of the
        -        // next chunk.
        -        lastWasSpace = trailingSpaceRe.test(htmlChunk);
        -        // IE collapses multiple adjacient <br>s into 1 line break.
        -        // Prefix every <br> with '&nbsp;' can prevent such IE's behavior.
        -        var lineBreakHtml = window['_pr_isIE6']() ? '&nbsp;<br />' : '<br />';
        -        html.push(htmlChunk.replace(newlineRe, lineBreakHtml));
        -        outputIdx = sourceIdx;
        -      }
        -    }
        -
        -    while (true) {
        -      // Determine if we're going to consume a tag this time around.  Otherwise
        -      // we consume a decoration or exit.
        -      var outputTag;
        -      if (tagPos < extractedTags.length) {
        -        if (decPos < decorations.length) {
        -          // Pick one giving preference to extractedTags since we shouldn't open
        -          // a new style that we're going to have to immediately close in order
        -          // to output a tag.
        -          outputTag = extractedTags[tagPos] <= decorations[decPos];
        -        } else {
        -          outputTag = true;
        -        }
        -      } else {
        -        outputTag = false;
        -      }
        -      // Consume either a decoration or a tag or exit.
        -      if (outputTag) {
        -        emitTextUpTo(extractedTags[tagPos]);
        -        if (openDecoration) {
        -          // Close the current decoration
        -          html.push('</span>');
        -          openDecoration = null;
        -        }
        -        html.push(extractedTags[tagPos + 1]);
        -        tagPos += 2;
        -      } else if (decPos < decorations.length) {
        -        emitTextUpTo(decorations[decPos]);
        -        currentDecoration = decorations[decPos + 1];
        -        decPos += 2;
        -      } else {
        -        break;
        -      }
        -    }
        -    emitTextUpTo(sourceText.length);
        -    if (openDecoration) {
        -      html.push('</span>');
        -    }
        -    job.prettyPrintedHtml = html.join('');
        -  }
        -
        -  /** Maps language-specific file extensions to handlers. */
        -  var langHandlerRegistry = {};
        -  /** Register a language handler for the given file extensions.
        -    * @param {function (Object)} handler a function from source code to a list
        -    *      of decorations.  Takes a single argument job which describes the
        -    *      state of the computation.   The single parameter has the form
        -    *      {@code {
        -    *        source: {string} as plain text.
        -    *        decorations: {Array.<number|string>} an array of style classes
        -    *                     preceded by the position at which they start in
        -    *                     job.source in order.
        -    *                     The language handler should assigned this field.
        -    *        basePos: {int} the position of source in the larger source chunk.
        -    *                 All positions in the output decorations array are relative
        -    *                 to the larger source chunk.
        -    *      } }
        -    * @param {Array.<string>} fileExtensions
        -    */
        -  function registerLangHandler(handler, fileExtensions) {
        -    for (var i = fileExtensions.length; --i >= 0;) {
        -      var ext = fileExtensions[i];
        -      if (!langHandlerRegistry.hasOwnProperty(ext)) {
        -        langHandlerRegistry[ext] = handler;
        -      } else if ('console' in window) {
        -        console.warn('cannot override language handler %s', ext);
        -      }
        -    }
        -  }
        -  function langHandlerForExtension(extension, source) {
        -    if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {
        -      // Treat it as markup if the first non whitespace character is a < and
        -      // the last non-whitespace character is a >.
        -      extension = /^\s*</.test(source)
        -          ? 'default-markup'
        -          : 'default-code';
        -    }
        -    return langHandlerRegistry[extension];
        -  }
        -  registerLangHandler(decorateSource, ['default-code']);
        -  registerLangHandler(
        -      createSimpleLexer(
        -          [],
        -          [
        -           [PR_PLAIN,       /^[^<?]+/],
        -           [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/],
        -           [PR_COMMENT,     /^<\!--[\s\S]*?(?:-\->|$)/],
        -           // Unescaped content in an unknown language
        -           ['lang-',        /^<\?([\s\S]+?)(?:\?>|$)/],
        -           ['lang-',        /^<%([\s\S]+?)(?:%>|$)/],
        -           [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],
        -           ['lang-',        /^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],
        -           // Unescaped content in javascript.  (Or possibly vbscript).
        -           ['lang-js',      /^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],
        -           // Contains unescaped stylesheet content
        -           ['lang-css',     /^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],
        -           ['lang-in.tag',  /^(<\/?[a-z][^<>]*>)/i]
        -          ]),
        -      ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);
        -  registerLangHandler(
        -      createSimpleLexer(
        -          [
        -           [PR_PLAIN,        /^[\s]+/, null, ' \t\r\n'],
        -           [PR_ATTRIB_VALUE, /^(?:\"[^\"]*\"?|\'[^\']*\'?)/, null, '\"\'']
        -           ],
        -          [
        -           [PR_TAG,          /^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],
        -           [PR_ATTRIB_NAME,  /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],
        -           ['lang-uq.val',   /^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],
        -           [PR_PUNCTUATION,  /^[=<>\/]+/],
        -           ['lang-js',       /^on\w+\s*=\s*\"([^\"]+)\"/i],
        -           ['lang-js',       /^on\w+\s*=\s*\'([^\']+)\'/i],
        -           ['lang-js',       /^on\w+\s*=\s*([^\"\'>\s]+)/i],
        -           ['lang-css',      /^style\s*=\s*\"([^\"]+)\"/i],
        -           ['lang-css',      /^style\s*=\s*\'([^\']+)\'/i],
        -           ['lang-css',      /^style\s*=\s*([^\"\'>\s]+)/i]
        -           ]),
        -      ['in.tag']);
        -  registerLangHandler(
        -      createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\s\S]+/]]), ['uq.val']);
        -  registerLangHandler(sourceDecorator({
        -          'keywords': CPP_KEYWORDS,
        -          'hashComments': true,
        -          'cStyleComments': true
        -        }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);
        -  registerLangHandler(sourceDecorator({
        -          'keywords': 'null true false'
        -        }), ['json']);
        -  registerLangHandler(sourceDecorator({
        -          'keywords': CSHARP_KEYWORDS,
        -          'hashComments': true,
        -          'cStyleComments': true,
        -          'verbatimStrings': true
        -        }), ['cs']);
        -  registerLangHandler(sourceDecorator({
        -          'keywords': JAVA_KEYWORDS,
        -          'cStyleComments': true
        -        }), ['java']);
        -  registerLangHandler(sourceDecorator({
        -          'keywords': SH_KEYWORDS,
        -          'hashComments': true,
        -          'multiLineStrings': true
        -        }), ['bsh', 'csh', 'sh']);
        -  registerLangHandler(sourceDecorator({
        -          'keywords': PYTHON_KEYWORDS,
        -          'hashComments': true,
        -          'multiLineStrings': true,
        -          'tripleQuotedStrings': true
        -        }), ['cv', 'py']);
        -  registerLangHandler(sourceDecorator({
        -          'keywords': PERL_KEYWORDS,
        -          'hashComments': true,
        -          'multiLineStrings': true,
        -          'regexLiterals': true
        -        }), ['perl', 'pl', 'pm']);
        -  registerLangHandler(sourceDecorator({
        -          'keywords': RUBY_KEYWORDS,
        -          'hashComments': true,
        -          'multiLineStrings': true,
        -          'regexLiterals': true
        -        }), ['rb']);
        -  registerLangHandler(sourceDecorator({
        -          'keywords': JSCRIPT_KEYWORDS,
        -          'cStyleComments': true,
        -          'regexLiterals': true
        -        }), ['js']);
        -  registerLangHandler(
        -      createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']);
        -
        -  function applyDecorator(job) {
        -    var sourceCodeHtml = job.sourceCodeHtml;
        -    var opt_langExtension = job.langExtension;
        -
        -    // Prepopulate output in case processing fails with an exception.
        -    job.prettyPrintedHtml = sourceCodeHtml;
        -
        -    try {
        -      // Extract tags, and convert the source code to plain text.
        -      var sourceAndExtractedTags = extractTags(sourceCodeHtml);
        -      /** Plain text. @type {string} */
        -      var source = sourceAndExtractedTags.source;
        -      job.source = source;
        -      job.basePos = 0;
        -
        -      /** Even entries are positions in source in ascending order.  Odd entries
        -        * are tags that were extracted at that position.
        -        * @type {Array.<number|string>}
        -        */
        -      job.extractedTags = sourceAndExtractedTags.tags;
        -
        -      // Apply the appropriate language handler
        -      langHandlerForExtension(opt_langExtension, source)(job);
        -      // Integrate the decorations and tags back into the source code to produce
        -      // a decorated html string which is left in job.prettyPrintedHtml.
        -      recombineTagsAndDecorations(job);
        -    } catch (e) {
        -      if ('console' in window) {
        -        console.log(e);
        -        console.trace();
        -      }
        -    }
        -  }
        -
        -  function prettyPrintOne(sourceCodeHtml, opt_langExtension) {
        -    var job = {
        -      sourceCodeHtml: sourceCodeHtml,
        -      langExtension: opt_langExtension
        -    };
        -    applyDecorator(job);
        -    return job.prettyPrintedHtml;
        -  }
        -
        -  function prettyPrint(opt_whenDone) {
        -    var isIE678 = window['_pr_isIE6']();
        -    var ieNewline = isIE678 === 6 ? '\r\n' : '\r';
        -    // See bug 71 and http://stackoverflow.com/questions/136443/why-doesnt-ie7-
        -
        -    // fetch a list of nodes to rewrite
        -    var codeSegments = [
        -        document.getElementsByTagName('pre'),
        -        document.getElementsByTagName('code'),
        -        document.getElementsByTagName('td'),  /* ND Change: Add tables to support prototypes. */
        -        document.getElementsByTagName('xmp') ];
        -    var elements = [];
        -    for (var i = 0; i < codeSegments.length; ++i) {
        -      for (var j = 0, n = codeSegments[i].length; j < n; ++j) {
        -        elements.push(codeSegments[i][j]);
        -      }
        -    }
        -    codeSegments = null;
        -
        -    var clock = Date;
        -    if (!clock['now']) {
        -      clock = { 'now': function () { return (new Date).getTime(); } };
        -    }
        -
        -    // The loop is broken into a series of continuations to make sure that we
        -    // don't make the browser unresponsive when rewriting a large page.
        -    var k = 0;
        -    var prettyPrintingJob;
        -
        -    function doWork() {
        -      var endTime = (window['PR_SHOULD_USE_CONTINUATION'] ?
        -                     clock.now() + 250 /* ms */ :
        -                     Infinity);
        -      for (; k < elements.length && clock.now() < endTime; k++) {
        -        var cs = elements[k];
        -        if (cs.className && cs.className.indexOf('prettyprint') >= 0) {
        -          // If the classes includes a language extensions, use it.
        -          // Language extensions can be specified like
        -          //     <pre class="prettyprint lang-cpp">
        -          // the language extension "cpp" is used to find a language handler as
        -          // passed to PR_registerLangHandler.
        -          var langExtension = cs.className.match(/\blang-(\w+)\b/);
        -          if (langExtension) { langExtension = langExtension[1]; }
        -
        -          // make sure this is not nested in an already prettified element
        -          var nested = false;
        -          for (var p = cs.parentNode; p; p = p.parentNode) {
        -            if ((p.tagName === 'pre' || p.tagName === 'code' ||
        -                 p.tagName === 'xmp' || p.tagName === 'td') &&  /* ND Change: Add tables to support prototypes */
        -                p.className && p.className.indexOf('prettyprint') >= 0) {
        -              nested = true;
        -              break;
        -            }
        -          }
        -          if (!nested) {
        -            // fetch the content as a snippet of properly escaped HTML.
        -            // Firefox adds newlines at the end.
        -            var content = getInnerHtml(cs);
        -            content = content.replace(/(?:\r\n?|\n)$/, '');
        -
        -	  		/* ND Change: we need to preserve &nbsp;s so change them to a special character instead of a space. */
        -			content = content.replace(/&nbsp;/g, '\x11');
        -
        -            // do the pretty printing
        -            prettyPrintingJob = {
        -              sourceCodeHtml: content,
        -              langExtension: langExtension,
        -              sourceNode: cs
        -            };
        -            applyDecorator(prettyPrintingJob);
        -            replaceWithPrettyPrintedHtml();
        -          }
        -        }
        -      }
        -      if (k < elements.length) {
        -        // finish up in a continuation
        -        setTimeout(doWork, 250);
        -      } else if (opt_whenDone) {
        -        opt_whenDone();
        -      }
        -    }
        -
        -    function replaceWithPrettyPrintedHtml() {
        -      var newContent = prettyPrintingJob.prettyPrintedHtml;
        -      if (!newContent) { return; }
        -
        -      /* ND Change: Restore the preserved &nbsp;s.  */
        -	  newContent = newContent.replace(/\x11/g, '&nbsp;');
        -
        -      var cs = prettyPrintingJob.sourceNode;
        -
        -      // push the prettified html back into the tag.
        -      if (!isRawContent(cs)) {
        -        // just replace the old html with the new
        -        cs.innerHTML = newContent;
        -      } else {
        -        // we need to change the tag to a <pre> since <xmp>s do not allow
        -        // embedded tags such as the span tags used to attach styles to
        -        // sections of source code.
        -        var pre = document.createElement('PRE');
        -        for (var i = 0; i < cs.attributes.length; ++i) {
        -          var a = cs.attributes[i];
        -          if (a.specified) {
        -            var aname = a.name.toLowerCase();
        -            if (aname === 'class') {
        -              pre.className = a.value;  // For IE 6
        -            } else {
        -              pre.setAttribute(a.name, a.value);
        -            }
        -          }
        -        }
        -        pre.innerHTML = newContent;
        -
        -        // remove the old
        -        cs.parentNode.replaceChild(pre, cs);
        -        cs = pre;
        -      }
        -
        -      // Replace <br>s with line-feeds so that copying and pasting works
        -      // on IE 6.
        -      // Doing this on other browsers breaks lots of stuff since \r\n is
        -      // treated as two newlines on Firefox, and doing this also slows
        -      // down rendering.
        -      if (isIE678 && cs.tagName === 'PRE') {
        -        var lineBreaks = cs.getElementsByTagName('br');
        -        for (var j = lineBreaks.length; --j >= 0;) {
        -          var lineBreak = lineBreaks[j];
        -          lineBreak.parentNode.replaceChild(
        -              document.createTextNode(ieNewline), lineBreak);
        -        }
        -      }
        -    }
        -
        -    doWork();
        -  }
        -
        -  window['PR_normalizedHtml'] = normalizedHtml;
        -  window['prettyPrintOne'] = prettyPrintOne;
        -  window['prettyPrint'] = prettyPrint;
        -  window['PR'] = {
        -        'combinePrefixPatterns': combinePrefixPatterns,
        -        'createSimpleLexer': createSimpleLexer,
        -        'registerLangHandler': registerLangHandler,
        -        'sourceDecorator': sourceDecorator,
        -        'PR_ATTRIB_NAME': PR_ATTRIB_NAME,
        -        'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,
        -        'PR_COMMENT': PR_COMMENT,
        -        'PR_DECLARATION': PR_DECLARATION,
        -        'PR_KEYWORD': PR_KEYWORD,
        -        'PR_LITERAL': PR_LITERAL,
        -        'PR_NOCODE': PR_NOCODE,
        -        'PR_PLAIN': PR_PLAIN,
        -        'PR_PUNCTUATION': PR_PUNCTUATION,
        -        'PR_SOURCE': PR_SOURCE,
        -        'PR_STRING': PR_STRING,
        -        'PR_TAG': PR_TAG,
        -        'PR_TYPE': PR_TYPE
        -      };
        -})();
        -
        -
        -// ____________________________________________________________________________
        -
        -
        -
        -// Lua extension
        -
        -PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\r \xA0]+/,null,'	\n\r \xa0'],[PR.PR_STRING,/^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])*(?:\'|$))/,null,'\"\'']],[[PR.PR_COMMENT,/^--(?:\[(=*)\[[\s\S]*?(?:\]\1\]|$)|[^\r\n]*)/],[PR.PR_STRING,/^\[(=*)\[[\s\S]*?(?:\]\1\]|$)/],[PR.PR_KEYWORD,/^(?:and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,null],[PR.PR_LITERAL,/^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],[PR.PR_PLAIN,/^[a-z_]\w*/i],[PR.PR_PUNCTUATION,/^[^\w\t\n\r \xA0][^\w\t\n\r \xA0\"\'\-\+=]*/]]),['lua'])
        -
        -
        -// Haskell extension
        -
        -PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\x0B\x0C\r ]+/,null,'	\n\r '],[PR.PR_STRING,/^\"(?:[^\"\\\n\x0C\r]|\\[\s\S])*(?:\"|$)/,null,'\"'],[PR.PR_STRING,/^\'(?:[^\'\\\n\x0C\r]|\\[^&])\'?/,null,'\''],[PR.PR_LITERAL,/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+\-]?\d+)?)/i,null,'0123456789']],[[PR.PR_COMMENT,/^(?:(?:--+(?:[^\r\n\x0C]*)?)|(?:\{-(?:[^-]|-+[^-\}])*-\}))/],[PR.PR_KEYWORD,/^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^a-zA-Z0-9\']|$)/,null],[PR.PR_PLAIN,/^(?:[A-Z][\w\']*\.)*[a-zA-Z][\w\']*/],[PR.PR_PUNCTUATION,/^[^\t\n\x0B\x0C\r a-zA-Z0-9\'\"]+/]]),['hs'])
        -
        -
        -// ML extension
        -
        -PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\r \xA0]+/,null,'	\n\r \xa0'],[PR.PR_COMMENT,/^#(?:if[\t\n\r \xA0]+(?:[a-z_$][\w\']*|``[^\r\n\t`]*(?:``|$))|else|endif|light)/i,null,'#'],[PR.PR_STRING,/^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])*(?:\'|$))/,null,'\"\'']],[[PR.PR_COMMENT,/^(?:\/\/[^\r\n]*|\(\*[\s\S]*?\*\))/],[PR.PR_KEYWORD,/^(?:abstract|and|as|assert|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|if|in|inherit|inline|interface|internal|lazy|let|match|member|module|mutable|namespace|new|null|of|open|or|override|private|public|rec|return|static|struct|then|to|true|try|type|upcast|use|val|void|when|while|with|yield|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|global|include|method|mixin|object|parallel|process|protected|pure|sealed|trait|virtual|volatile)\b/],[PR.PR_LITERAL,/^[+\-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],[PR.PR_PLAIN,/^(?:[a-z_]\w*[!?#]?|``[^\r\n\t`]*(?:``|$))/i],[PR.PR_PUNCTUATION,/^[^\t\n\r \xA0\"\'\w]+/]]),['fs','ml'])
        -
        -
        -// SQL extension
        -
        -PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\r \xA0]+/,null,'	\n\r \xa0'],[PR.PR_STRING,/^(?:"(?:[^\"\\]|\\.)*"|'(?:[^\'\\]|\\.)*')/,null,'\"\'']],[[PR.PR_COMMENT,/^(?:--[^\r\n]*|\/\*[\s\S]*?(?:\*\/|$))/],[PR.PR_KEYWORD,/^(?:ADD|ALL|ALTER|AND|ANY|AS|ASC|AUTHORIZATION|BACKUP|BEGIN|BETWEEN|BREAK|BROWSE|BULK|BY|CASCADE|CASE|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMN|COMMIT|COMPUTE|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATABASE|DBCC|DEALLOCATE|DECLARE|DEFAULT|DELETE|DENY|DESC|DISK|DISTINCT|DISTRIBUTED|DOUBLE|DROP|DUMMY|DUMP|ELSE|END|ERRLVL|ESCAPE|EXCEPT|EXEC|EXECUTE|EXISTS|EXIT|FETCH|FILE|FILLFACTOR|FOR|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GOTO|GRANT|GROUP|HAVING|HOLDLOCK|IDENTITY|IDENTITYCOL|IDENTITY_INSERT|IF|IN|INDEX|INNER|INSERT|INTERSECT|INTO|IS|JOIN|KEY|KILL|LEFT|LIKE|LINENO|LOAD|NATIONAL|NOCHECK|NONCLUSTERED|NOT|NULL|NULLIF|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPENXML|OPTION|OR|ORDER|OUTER|OVER|PERCENT|PLAN|PRECISION|PRIMARY|PRINT|PROC|PROCEDURE|PUBLIC|RAISERROR|READ|READTEXT|RECONFIGURE|REFERENCES|REPLICATION|RESTORE|RESTRICT|RETURN|REVOKE|RIGHT|ROLLBACK|ROWCOUNT|ROWGUIDCOL|RULE|SAVE|SCHEMA|SELECT|SESSION_USER|SET|SETUSER|SHUTDOWN|SOME|STATISTICS|SYSTEM_USER|TABLE|TEXTSIZE|THEN|TO|TOP|TRAN|TRANSACTION|TRIGGER|TRUNCATE|TSEQUAL|UNION|UNIQUE|UPDATE|UPDATETEXT|USE|USER|VALUES|VARYING|VIEW|WAITFOR|WHEN|WHERE|WHILE|WITH|WRITETEXT)(?=[^\w-]|$)/i,null],[PR.PR_LITERAL,/^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],[PR.PR_PLAIN,/^[a-z_][\w-]*/i],[PR.PR_PUNCTUATION,/^[^\w\t\n\r \xA0\"\'][^\w\t\n\r \xA0+\-\"\']*/]]),['sql'])
        -
        -
        -// VB extension
        -
        -PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\r \xA0\u2028\u2029]+/,null,'	\n\r \xa0\u2028\u2029'],[PR.PR_STRING,/^(?:[\"\u201C\u201D](?:[^\"\u201C\u201D]|[\"\u201C\u201D]{2})(?:[\"\u201C\u201D]c|$)|[\"\u201C\u201D](?:[^\"\u201C\u201D]|[\"\u201C\u201D]{2})*(?:[\"\u201C\u201D]|$))/i,null,'\"\u201c\u201d'],[PR.PR_COMMENT,/^[\'\u2018\u2019][^\r\n\u2028\u2029]*/,null,'\'\u2018\u2019']],[[PR.PR_KEYWORD,/^(?:AddHandler|AddressOf|Alias|And|AndAlso|Ansi|As|Assembly|Auto|Boolean|ByRef|Byte|ByVal|Call|Case|Catch|CBool|CByte|CChar|CDate|CDbl|CDec|Char|CInt|Class|CLng|CObj|Const|CShort|CSng|CStr|CType|Date|Decimal|Declare|Default|Delegate|Dim|DirectCast|Do|Double|Each|Else|ElseIf|End|EndIf|Enum|Erase|Error|Event|Exit|Finally|For|Friend|Function|Get|GetType|GoSub|GoTo|Handles|If|Implements|Imports|In|Inherits|Integer|Interface|Is|Let|Lib|Like|Long|Loop|Me|Mod|Module|MustInherit|MustOverride|MyBase|MyClass|Namespace|New|Next|Not|NotInheritable|NotOverridable|Object|On|Option|Optional|Or|OrElse|Overloads|Overridable|Overrides|ParamArray|Preserve|Private|Property|Protected|Public|RaiseEvent|ReadOnly|ReDim|RemoveHandler|Resume|Return|Select|Set|Shadows|Shared|Short|Single|Static|Step|Stop|String|Structure|Sub|SyncLock|Then|Throw|To|Try|TypeOf|Unicode|Until|Variant|Wend|When|While|With|WithEvents|WriteOnly|Xor|EndIf|GoSub|Let|Variant|Wend)\b/i,null],[PR.PR_COMMENT,/^REM[^\r\n\u2028\u2029]*/i],[PR.PR_LITERAL,/^(?:True\b|False\b|Nothing\b|\d+(?:E[+\-]?\d+[FRD]?|[FRDSIL])?|(?:&H[0-9A-F]+|&O[0-7]+)[SIL]?|\d*\.\d+(?:E[+\-]?\d+)?[FRD]?|#\s+(?:\d+[\-\/]\d+[\-\/]\d+(?:\s+\d+:\d+(?::\d+)?(\s*(?:AM|PM))?)?|\d+:\d+(?::\d+)?(\s*(?:AM|PM))?)\s+#)/i],[PR.PR_PLAIN,/^(?:(?:[a-z]|_\w)\w*|\[(?:[a-z]|_\w)\w*\])/i],[PR.PR_PUNCTUATION,/^[^\w\t\n\r \"\'\[\]\xA0\u2018\u2019\u201C\u201D\u2028\u2029]+/],[PR.PR_PUNCTUATION,/^(?:\[|\])/]]),['vb','vbs'])
        diff --git a/vendor/naturaldocs/JavaScript/NaturalDocs.js b/vendor/naturaldocs/JavaScript/NaturalDocs.js
        deleted file mode 100644
        index 3f42acde6..000000000
        --- a/vendor/naturaldocs/JavaScript/NaturalDocs.js
        +++ /dev/null
        @@ -1,841 +0,0 @@
        -// This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -// Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -// Refer to License.txt for the complete details
        -
        -// This file may be distributed with documentation files generated by Natural Docs.
        -// Such documentation is not covered by Natural Docs' copyright and licensing,
        -// and may have its own copyright and distribution terms as decided by its author.
        -
        -
        -//
        -//  Browser Styles
        -// ____________________________________________________________________________
        -
        -var agt=navigator.userAgent.toLowerCase();
        -var browserType;
        -var browserVer;
        -
        -if (agt.indexOf("opera") != -1)
        -    {
        -    browserType = "Opera";
        -
        -    if (agt.indexOf("opera 7") != -1 || agt.indexOf("opera/7") != -1)
        -        {  browserVer = "Opera7";  }
        -    else if (agt.indexOf("opera 8") != -1 || agt.indexOf("opera/8") != -1)
        -        {  browserVer = "Opera8";  }
        -    else if (agt.indexOf("opera 9") != -1 || agt.indexOf("opera/9") != -1)
        -        {  browserVer = "Opera9";  }
        -    }
        -
        -else if (agt.indexOf("applewebkit") != -1)
        -    {
        -    browserType = "Safari";
        -
        -    if (agt.indexOf("version/3") != -1)
        -        {  browserVer = "Safari3";  }
        -    else if (agt.indexOf("safari/4") != -1)
        -        {  browserVer = "Safari2";  }
        -    }
        -
        -else if (agt.indexOf("khtml") != -1)
        -    {
        -    browserType = "Konqueror";
        -    }
        -
        -else if (agt.indexOf("msie") != -1)
        -    {
        -    browserType = "IE";
        -
        -    if (agt.indexOf("msie 6") != -1)
        -        {  browserVer = "IE6";  }
        -    else if (agt.indexOf("msie 7") != -1)
        -        {  browserVer = "IE7";  }
        -    }
        -
        -else if (agt.indexOf("gecko") != -1)
        -    {
        -    browserType = "Firefox";
        -
        -    if (agt.indexOf("rv:1.7") != -1)
        -        {  browserVer = "Firefox1";  }
        -    else if (agt.indexOf("rv:1.8)") != -1 || agt.indexOf("rv:1.8.0") != -1)
        -        {  browserVer = "Firefox15";  }
        -    else if (agt.indexOf("rv:1.8.1") != -1)
        -        {  browserVer = "Firefox2";  }
        -    }
        -
        -
        -//
        -//  Support Functions
        -// ____________________________________________________________________________
        -
        -
        -function GetXPosition(item)
        -    {
        -    var position = 0;
        -
        -    if (item.offsetWidth != null)
        -        {
        -        while (item != document.body && item != null)
        -            {
        -            position += item.offsetLeft;
        -            item = item.offsetParent;
        -            };
        -        };
        -
        -    return position;
        -    };
        -
        -
        -function GetYPosition(item)
        -    {
        -    var position = 0;
        -
        -    if (item.offsetWidth != null)
        -        {
        -        while (item != document.body && item != null)
        -            {
        -            position += item.offsetTop;
        -            item = item.offsetParent;
        -            };
        -        };
        -
        -    return position;
        -    };
        -
        -
        -function MoveToPosition(item, x, y)
        -    {
        -    // Opera 5 chokes on the px extension, so it can use the Microsoft one instead.
        -
        -    if (item.style.left != null)
        -        {
        -        item.style.left = x + "px";
        -        item.style.top = y + "px";
        -        }
        -    else if (item.style.pixelLeft != null)
        -        {
        -        item.style.pixelLeft = x;
        -        item.style.pixelTop = y;
        -        };
        -    };
        -
        -
        -//
        -//  Menu
        -// ____________________________________________________________________________
        -
        -
        -function ToggleMenu(id)
        -    {
        -    if (!window.document.getElementById)
        -        {  return;  };
        -
        -    var display = window.document.getElementById(id).style.display;
        -
        -    if (display == "none")
        -        {  display = "block";  }
        -    else
        -        {  display = "none";  }
        -
        -    window.document.getElementById(id).style.display = display;
        -    }
        -
        -function HideAllBut(ids, max)
        -    {
        -    if (document.getElementById)
        -        {
        -        ids.sort( function(a,b) { return a - b; } );
        -        var number = 1;
        -
        -        while (number < max)
        -            {
        -            if (ids.length > 0 && number == ids[0])
        -                {  ids.shift();  }
        -            else
        -                {
        -                document.getElementById("MGroupContent" + number).style.display = "none";
        -                };
        -
        -            number++;
        -            };
        -        };
        -    }
        -
        -
        -//
        -//  Tooltips
        -// ____________________________________________________________________________
        -
        -
        -var tooltipTimer = 0;
        -
        -function ShowTip(event, tooltipID, linkID)
        -    {
        -    if (tooltipTimer)
        -        {  clearTimeout(tooltipTimer);  };
        -
        -    var docX = event.clientX + window.pageXOffset;
        -    var docY = event.clientY + window.pageYOffset;
        -
        -    var showCommand = "ReallyShowTip('" + tooltipID + "', '" + linkID + "', " + docX + ", " + docY + ")";
        -
        -    tooltipTimer = setTimeout(showCommand, 1000);
        -    }
        -
        -function ReallyShowTip(tooltipID, linkID, docX, docY)
        -    {
        -    tooltipTimer = 0;
        -
        -    var tooltip;
        -    var link;
        -
        -    if (document.getElementById)
        -        {
        -        tooltip = document.getElementById(tooltipID);
        -        link = document.getElementById(linkID);
        -        }
        -/*    else if (document.all)
        -        {
        -        tooltip = eval("document.all['" + tooltipID + "']");
        -        link = eval("document.all['" + linkID + "']");
        -        }
        -*/
        -    if (tooltip)
        -        {
        -        var left = GetXPosition(link);
        -        var top = GetYPosition(link);
        -        top += link.offsetHeight;
        -
        -
        -        // The fallback method is to use the mouse X and Y relative to the document.  We use a separate if and test if its a number
        -        // in case some browser snuck through the above if statement but didn't support everything.
        -
        -        if (!isFinite(top) || top == 0)
        -            {
        -            left = docX;
        -            top = docY;
        -            }
        -
        -        // Some spacing to get it out from under the cursor.
        -
        -        top += 10;
        -
        -        // Make sure the tooltip doesnt get smushed by being too close to the edge, or in some browsers, go off the edge of the
        -        // page.  We do it here because Konqueror does get offsetWidth right even if it doesnt get the positioning right.
        -
        -        if (tooltip.offsetWidth != null)
        -            {
        -            var width = tooltip.offsetWidth;
        -            var docWidth = document.body.clientWidth;
        -
        -            if (left + width > docWidth)
        -                {  left = docWidth - width - 1;  }
        -
        -            // If there's a horizontal scroll bar we could go past zero because it's using the page width, not the window width.
        -            if (left < 0)
        -                {  left = 0;  };
        -            }
        -
        -        MoveToPosition(tooltip, left, top);
        -        tooltip.style.visibility = "visible";
        -        }
        -    }
        -
        -function HideTip(tooltipID)
        -    {
        -    if (tooltipTimer)
        -        {
        -        clearTimeout(tooltipTimer);
        -        tooltipTimer = 0;
        -        }
        -
        -    var tooltip;
        -
        -    if (document.getElementById)
        -        {  tooltip = document.getElementById(tooltipID); }
        -    else if (document.all)
        -        {  tooltip = eval("document.all['" + tooltipID + "']");  }
        -
        -    if (tooltip)
        -        {  tooltip.style.visibility = "hidden";  }
        -    }
        -
        -
        -//
        -//  Blockquote fix for IE
        -// ____________________________________________________________________________
        -
        -
        -function NDOnLoad()
        -    {
        -    if (browserVer == "IE6")
        -        {
        -        var scrollboxes = document.getElementsByTagName('blockquote');
        -
        -        if (scrollboxes.item(0))
        -            {
        -            NDDoResize();
        -            window.onresize=NDOnResize;
        -            };
        -        };
        -    };
        -
        -
        -var resizeTimer = 0;
        -
        -function NDOnResize()
        -    {
        -    if (resizeTimer != 0)
        -        {  clearTimeout(resizeTimer);  };
        -
        -    resizeTimer = setTimeout(NDDoResize, 250);
        -    };
        -
        -
        -function NDDoResize()
        -    {
        -    var scrollboxes = document.getElementsByTagName('blockquote');
        -
        -    var i;
        -    var item;
        -
        -    i = 0;
        -    while (item = scrollboxes.item(i))
        -        {
        -        item.style.width = 100;
        -        i++;
        -        };
        -
        -    i = 0;
        -    while (item = scrollboxes.item(i))
        -        {
        -        item.style.width = item.parentNode.offsetWidth;
        -        i++;
        -        };
        -
        -    clearTimeout(resizeTimer);
        -    resizeTimer = 0;
        -    }
        -
        -
        -
        -/* ________________________________________________________________________________________________________
        -
        -    Class: SearchPanel
        -    ________________________________________________________________________________________________________
        -
        -    A class handling everything associated with the search panel.
        -
        -    Parameters:
        -
        -        name - The name of the global variable that will be storing this instance.  Is needed to be able to set timeouts.
        -        mode - The mode the search is going to work in.  Pass <NaturalDocs::Builder::Base->CommandLineOption()>, so the
        -                   value will be something like "HTML" or "FramedHTML".
        -
        -    ________________________________________________________________________________________________________
        -*/
        -
        -
        -function SearchPanel(name, mode, resultsPath)
        -    {
        -    if (!name || !mode || !resultsPath)
        -        {  alert("Incorrect parameters to SearchPanel.");  };
        -
        -
        -    // Group: Variables
        -    // ________________________________________________________________________
        -
        -    /*
        -        var: name
        -        The name of the global variable that will be storing this instance of the class.
        -    */
        -    this.name = name;
        -
        -    /*
        -        var: mode
        -        The mode the search is going to work in, such as "HTML" or "FramedHTML".
        -    */
        -    this.mode = mode;
        -
        -    /*
        -        var: resultsPath
        -        The relative path from the current HTML page to the results page directory.
        -    */
        -    this.resultsPath = resultsPath;
        -
        -    /*
        -        var: keyTimeout
        -        The timeout used between a keystroke and when a search is performed.
        -    */
        -    this.keyTimeout = 0;
        -
        -    /*
        -        var: keyTimeoutLength
        -        The length of <keyTimeout> in thousandths of a second.
        -    */
        -    this.keyTimeoutLength = 500;
        -
        -    /*
        -        var: lastSearchValue
        -        The last search string executed, or an empty string if none.
        -    */
        -    this.lastSearchValue = "";
        -
        -    /*
        -        var: lastResultsPage
        -        The last results page.  The value is only relevant if <lastSearchValue> is set.
        -    */
        -    this.lastResultsPage = "";
        -
        -    /*
        -        var: deactivateTimeout
        -
        -        The timeout used between when a control is deactivated and when the entire panel is deactivated.  Is necessary
        -        because a control may be deactivated in favor of another control in the same panel, in which case it should stay
        -        active.
        -    */
        -    this.deactivateTimout = 0;
        -
        -    /*
        -        var: deactivateTimeoutLength
        -        The length of <deactivateTimeout> in thousandths of a second.
        -    */
        -    this.deactivateTimeoutLength = 200;
        -
        -
        -
        -
        -    // Group: DOM Elements
        -    // ________________________________________________________________________
        -
        -
        -    // Function: DOMSearchField
        -    this.DOMSearchField = function()
        -        {  return document.getElementById("MSearchField");  };
        -
        -    // Function: DOMSearchType
        -    this.DOMSearchType = function()
        -        {  return document.getElementById("MSearchType");  };
        -
        -    // Function: DOMPopupSearchResults
        -    this.DOMPopupSearchResults = function()
        -        {  return document.getElementById("MSearchResults");  };
        -
        -    // Function: DOMPopupSearchResultsWindow
        -    this.DOMPopupSearchResultsWindow = function()
        -        {  return document.getElementById("MSearchResultsWindow");  };
        -
        -    // Function: DOMSearchPanel
        -    this.DOMSearchPanel = function()
        -        {  return document.getElementById("MSearchPanel");  };
        -
        -
        -
        -
        -    // Group: Event Handlers
        -    // ________________________________________________________________________
        -
        -
        -    /*
        -        Function: OnSearchFieldFocus
        -        Called when focus is added or removed from the search field.
        -    */
        -    this.OnSearchFieldFocus = function(isActive)
        -        {
        -        this.Activate(isActive);
        -        };
        -
        -
        -    /*
        -        Function: OnSearchFieldChange
        -        Called when the content of the search field is changed.
        -    */
        -    this.OnSearchFieldChange = function()
        -        {
        -        if (this.keyTimeout)
        -            {
        -            clearTimeout(this.keyTimeout);
        -            this.keyTimeout = 0;
        -            };
        -
        -        var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
        -
        -        if (searchValue != this.lastSearchValue)
        -            {
        -            if (searchValue != "")
        -                {
        -                this.keyTimeout = setTimeout(this.name + ".Search()", this.keyTimeoutLength);
        -                }
        -            else
        -                {
        -                if (this.mode == "HTML")
        -                    {  this.DOMPopupSearchResultsWindow().style.display = "none";  };
        -                this.lastSearchValue = "";
        -                };
        -            };
        -        };
        -
        -
        -    /*
        -        Function: OnSearchTypeFocus
        -        Called when focus is added or removed from the search type.
        -    */
        -    this.OnSearchTypeFocus = function(isActive)
        -        {
        -        this.Activate(isActive);
        -        };
        -
        -
        -    /*
        -        Function: OnSearchTypeChange
        -        Called when the search type is changed.
        -    */
        -    this.OnSearchTypeChange = function()
        -        {
        -        var searchValue = this.DOMSearchField().value.replace(/ +/g, "");
        -
        -        if (searchValue != "")
        -            {
        -            this.Search();
        -            };
        -        };
        -
        -
        -
        -    // Group: Action Functions
        -    // ________________________________________________________________________
        -
        -
        -    /*
        -        Function: CloseResultsWindow
        -        Closes the results window.
        -    */
        -    this.CloseResultsWindow = function()
        -        {
        -        this.DOMPopupSearchResultsWindow().style.display = "none";
        -        this.Activate(false, true);
        -        };
        -
        -
        -    /*
        -        Function: Search
        -        Performs a search.
        -    */
        -    this.Search = function()
        -        {
        -        this.keyTimeout = 0;
        -
        -        var searchValue = this.DOMSearchField().value.replace(/^ +/, "");
        -        var searchTopic = this.DOMSearchType().value;
        -
        -        var pageExtension = searchValue.substr(0,1);
        -
        -        if (pageExtension.match(/^[a-z]/i))
        -            {  pageExtension = pageExtension.toUpperCase();  }
        -        else if (pageExtension.match(/^[0-9]/))
        -            {  pageExtension = 'Numbers';  }
        -        else
        -            {  pageExtension = "Symbols";  };
        -
        -        var resultsPage;
        -        var resultsPageWithSearch;
        -        var hasResultsPage;
        -
        -        // indexSectionsWithContent is defined in searchdata.js
        -        if (indexSectionsWithContent[searchTopic][pageExtension] == true)
        -            {
        -            resultsPage = this.resultsPath + '/' + searchTopic + pageExtension + '.html';
        -            resultsPageWithSearch = resultsPage+'?'+escape(searchValue);
        -            hasResultsPage = true;
        -            }
        -        else
        -            {
        -            resultsPage = this.resultsPath + '/NoResults.html';
        -            resultsPageWithSearch = resultsPage;
        -            hasResultsPage = false;
        -            };
        -
        -        var resultsFrame;
        -        if (this.mode == "HTML")
        -            {  resultsFrame = window.frames.MSearchResults;  }
        -        else if (this.mode == "FramedHTML")
        -            {  resultsFrame = window.top.frames['Content'];  };
        -
        -
        -        if (resultsPage != this.lastResultsPage ||
        -
        -            // Bug in IE.  If everything becomes hidden in a run, none of them will be able to be reshown in the next for some
        -            // reason.  It counts the right number of results, and you can even read the display as "block" after setting it, but it
        -            // just doesn't work in IE 6 or IE 7.  So if we're on the right page but the previous search had no results, reload the
        -            // page anyway to get around the bug.
        -            (browserType == "IE" && hasResultsPage &&
        -            	(!resultsFrame.searchResults || resultsFrame.searchResults.lastMatchCount == 0)) )
        -
        -            {
        -            resultsFrame.location.href = resultsPageWithSearch;
        -            }
        -
        -        // So if the results page is right and there's no IE bug, reperform the search on the existing page.  We have to check if there
        -        // are results because NoResults.html doesn't have any JavaScript, and it would be useless to do anything on that page even
        -        // if it did.
        -        else if (hasResultsPage)
        -            {
        -            // We need to check if this exists in case the frame is present but didn't finish loading.
        -            if (resultsFrame.searchResults)
        -                {  resultsFrame.searchResults.Search(searchValue);  }
        -
        -            // Otherwise just reload instead of waiting.
        -            else
        -                {  resultsFrame.location.href = resultsPageWithSearch;  };
        -            };
        -
        -
        -        var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow();
        -
        -        if (this.mode == "HTML" && domPopupSearchResultsWindow.style.display != "block")
        -            {
        -            var domSearchType = this.DOMSearchType();
        -
        -            var left = GetXPosition(domSearchType);
        -            var top = GetYPosition(domSearchType) + domSearchType.offsetHeight;
        -
        -            MoveToPosition(domPopupSearchResultsWindow, left, top);
        -            domPopupSearchResultsWindow.style.display = 'block';
        -            };
        -
        -
        -        this.lastSearchValue = searchValue;
        -        this.lastResultsPage = resultsPage;
        -        };
        -
        -
        -
        -    // Group: Activation Functions
        -    // Functions that handle whether the entire panel is active or not.
        -    // ________________________________________________________________________
        -
        -
        -    /*
        -        Function: Activate
        -
        -        Activates or deactivates the search panel, resetting things to their default values if necessary.  You can call this on every
        -        control's OnBlur() and it will handle not deactivating the entire panel when focus is just switching between them transparently.
        -
        -        Parameters:
        -
        -            isActive - Whether you're activating or deactivating the panel.
        -            ignoreDeactivateDelay - Set if you're positive the action will deactivate the panel and thus want to skip the delay.
        -    */
        -    this.Activate = function(isActive, ignoreDeactivateDelay)
        -        {
        -        // We want to ignore isActive being false while the results window is open.
        -        if (isActive || (this.mode == "HTML" && this.DOMPopupSearchResultsWindow().style.display == "block"))
        -            {
        -            if (this.inactivateTimeout)
        -                {
        -                clearTimeout(this.inactivateTimeout);
        -                this.inactivateTimeout = 0;
        -                };
        -
        -            this.DOMSearchPanel().className = 'MSearchPanelActive';
        -
        -            var searchField = this.DOMSearchField();
        -
        -            if (searchField.value == 'Search')
        -                 {  searchField.value = "";  }
        -            }
        -        else if (!ignoreDeactivateDelay)
        -            {
        -            this.inactivateTimeout = setTimeout(this.name + ".InactivateAfterTimeout()", this.inactivateTimeoutLength);
        -            }
        -        else
        -            {
        -            this.InactivateAfterTimeout();
        -            };
        -        };
        -
        -
        -    /*
        -        Function: InactivateAfterTimeout
        -
        -        Called by <inactivateTimeout>, which is set by <Activate()>.  Inactivation occurs on a timeout because a control may
        -        receive OnBlur() when focus is really transferring to another control in the search panel.  In this case we don't want to
        -        actually deactivate the panel because not only would that cause a visible flicker but it could also reset the search value.
        -        So by doing it on a timeout instead, there's a short period where the second control's OnFocus() can cancel the deactivation.
        -    */
        -    this.InactivateAfterTimeout = function()
        -        {
        -        this.inactivateTimeout = 0;
        -
        -        this.DOMSearchPanel().className = 'MSearchPanelInactive';
        -        this.DOMSearchField().value = "Search";
        -
        -	    this.lastSearchValue = "";
        -	    this.lastResultsPage = "";
        -        };
        -    };
        -
        -
        -
        -
        -/* ________________________________________________________________________________________________________
        -
        -   Class: SearchResults
        -   _________________________________________________________________________________________________________
        -
        -   The class that handles everything on the search results page.
        -   _________________________________________________________________________________________________________
        -*/
        -
        -
        -function SearchResults(name, mode)
        -    {
        -    /*
        -        var: mode
        -        The mode the search is going to work in, such as "HTML" or "FramedHTML".
        -    */
        -    this.mode = mode;
        -
        -    /*
        -        var: lastMatchCount
        -        The number of matches from the last run of <Search()>.
        -    */
        -    this.lastMatchCount = 0;
        -
        -
        -    /*
        -        Function: Toggle
        -        Toggles the visibility of the passed element ID.
        -    */
        -    this.Toggle = function(id)
        -        {
        -        if (this.mode == "FramedHTML")
        -            {  return;  };
        -
        -        var parentElement = document.getElementById(id);
        -
        -        var element = parentElement.firstChild;
        -
        -        while (element && element != parentElement)
        -            {
        -            if (element.nodeName == 'DIV' && element.className == 'ISubIndex')
        -                {
        -                if (element.style.display == 'block')
        -                    {  element.style.display = "none";  }
        -                else
        -                    {  element.style.display = 'block';  }
        -                };
        -
        -            if (element.nodeName == 'DIV' && element.hasChildNodes())
        -                {  element = element.firstChild;  }
        -            else if (element.nextSibling)
        -                {  element = element.nextSibling;  }
        -            else
        -                {
        -                do
        -                    {
        -                    element = element.parentNode;
        -                    }
        -                while (element && element != parentElement && !element.nextSibling);
        -
        -                if (element && element != parentElement)
        -                    {  element = element.nextSibling;  };
        -                };
        -            };
        -        };
        -
        -
        -    /*
        -        Function: Search
        -
        -        Searches for the passed string.  If there is no parameter, it takes it from the URL query.
        -
        -        Always returns true, since other documents may try to call it and that may or may not be possible.
        -    */
        -    this.Search = function(search)
        -        {
        -        if (!search)
        -            {
        -            search = window.location.search;
        -            search = search.substring(1);  // Remove the leading ?
        -            search = unescape(search);
        -            };
        -
        -        search = search.replace(/^ +/, "");
        -        search = search.replace(/ +$/, "");
        -        search = search.toLowerCase();
        -
        -        if (search.match(/[^a-z0-9]/)) // Just a little speedup so it doesn't have to go through the below unnecessarily.
        -            {
        -            search = search.replace(/\_/g, "_und");
        -            search = search.replace(/\ +/gi, "_spc");
        -            search = search.replace(/\~/g, "_til");
        -            search = search.replace(/\!/g, "_exc");
        -            search = search.replace(/\@/g, "_att");
        -            search = search.replace(/\#/g, "_num");
        -            search = search.replace(/\$/g, "_dol");
        -            search = search.replace(/\%/g, "_pct");
        -            search = search.replace(/\^/g, "_car");
        -            search = search.replace(/\&/g, "_amp");
        -            search = search.replace(/\*/g, "_ast");
        -            search = search.replace(/\(/g, "_lpa");
        -            search = search.replace(/\)/g, "_rpa");
        -            search = search.replace(/\-/g, "_min");
        -            search = search.replace(/\+/g, "_plu");
        -            search = search.replace(/\=/g, "_equ");
        -            search = search.replace(/\{/g, "_lbc");
        -            search = search.replace(/\}/g, "_rbc");
        -            search = search.replace(/\[/g, "_lbk");
        -            search = search.replace(/\]/g, "_rbk");
        -            search = search.replace(/\:/g, "_col");
        -            search = search.replace(/\;/g, "_sco");
        -            search = search.replace(/\"/g, "_quo");
        -            search = search.replace(/\'/g, "_apo");
        -            search = search.replace(/\</g, "_lan");
        -            search = search.replace(/\>/g, "_ran");
        -            search = search.replace(/\,/g, "_com");
        -            search = search.replace(/\./g, "_per");
        -            search = search.replace(/\?/g, "_que");
        -            search = search.replace(/\//g, "_sla");
        -            search = search.replace(/[^a-z0-9\_]i/gi, "_zzz");
        -            };
        -
        -        var resultRows = document.getElementsByTagName("div");
        -        var matches = 0;
        -
        -        var i = 0;
        -        while (i < resultRows.length)
        -            {
        -            var row = resultRows.item(i);
        -
        -            if (row.className == "SRResult")
        -                {
        -                var rowMatchName = row.id.toLowerCase();
        -                rowMatchName = rowMatchName.replace(/^sr\d*_/, '');
        -
        -                if (search.length <= rowMatchName.length && rowMatchName.substr(0, search.length) == search)
        -                    {
        -                    row.style.display = "block";
        -                    matches++;
        -                    }
        -                else
        -                    {  row.style.display = "none";  };
        -                };
        -
        -            i++;
        -            };
        -
        -        document.getElementById("Searching").style.display="none";
        -
        -        if (matches == 0)
        -            {  document.getElementById("NoMatches").style.display="block";  }
        -        else
        -            {  document.getElementById("NoMatches").style.display="none";  }
        -
        -        this.lastMatchCount = matches;
        -
        -        return true;
        -        };
        -    };
        -
        diff --git a/vendor/naturaldocs/License.txt b/vendor/naturaldocs/License.txt
        deleted file mode 100644
        index 70aabbed8..000000000
        --- a/vendor/naturaldocs/License.txt
        +++ /dev/null
        @@ -1,275 +0,0 @@
        -Title: License
        -
        -Natural Docs is Copyright © 2003-2010 Greg Valure.  Natural Docs is licensed under version 3 of the GNU
        -Affero General Public License (AGPL).
        -
        -Natural Docs incorporates code from Google Prettify, which is Copyright © 2006 Google Inc.  Google Prettify
        -may be obtained separately under version 2.0 of the Apache License.  However, this combined product is still
        -licensed under the terms of the AGPLv3.
        -
        -Portions of Natural Docs may be distributed with generated documentation files in order to help them function,
        -such as JavaScript and CSS files.  These individual files retain their copyright and licensing terms, but they do
        -not apply to the remainder of the generated documentation.  All other generated documentation files remain
        -under the copyright and distribution terms decided by its author(s).
        -
        -
        -Topic: GNU Affero General Public License
        -
        -	Version 3, 19 November 2007
        -
        -	Copyright © 2007 Free Software Foundation, Inc.  <http://fsf.org/>
        -
        -	Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
        -
        -
        -	Preamble:
        -
        -	The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software.
        -
        -	The licenses for most software and other practical works are designed to take away your freedom to share and change the works.  By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.
        -
        -	When we speak of free software, we are referring to freedom, not price.  Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
        -
        -	Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software.
        -
        -	A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate.  Many developers of free software are heartened and encouraged by the resulting cooperation.  However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public.
        -
        -	The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community.  It requires the operator of a network server to provide the source code of the modified version running there to the users of that server.  Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version.
        -
        -	An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals.  This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license.
        -
        -	The precise terms and conditions for copying, distribution and modification follow.
        -
        -
        -	TERMS AND CONDITIONS:
        -
        -	0. Definitions:
        -
        -	"This License" refers to version 3 of the GNU Affero General Public License.
        -
        -	"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
        -
        -	"The Program" refers to any copyrightable work licensed under this License.  Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations
        -
        -	To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy.  The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.
        -
        -	A "covered work" means either the unmodified Program or a work based on the Program.
        -
        -	To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy.  Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
        -
        -	To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
        -
        -	An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this
        -	License, and how to view a copy of this License.  If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
        -
        -
        -	1. Source Code:
        -
        -	The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.
        -
        -	A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
        -
        -	The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
        -
        -	The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
        -
        -	The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
        -
        -	The Corresponding Source for a work in source code form is that same work.
        -
        -
        -	2. Basic Permissions:
        -
        -	All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
        -
        -	You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
        -
        -	Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
        -
        -
        -	3. Protecting Users' Legal Rights From Anti-Circumvention Law:
        -
        -	No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
        -
        -	When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
        -
        -
        -	4. Conveying Verbatim Copies:
        -
        -	You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
        -
        -	You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
        -
        -
        -	5. Conveying Modified Source Versions:
        -
        -	You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code
        -under the terms of section 4, provided that you also meet all of these conditions:
        -
        -	    * a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
        -	    * b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".
        -	    * c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
        -	    * d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
        -
        -	A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
        -
        -
        -	6. Conveying Non-Source Forms:
        -
        -	You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the
        -machine-readable Corresponding Source under the terms of this License, in one of these ways:
        -
        -	    * a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
        -	    * b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
        -	    * c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
        -	    * d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
        -	    * e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
        -
        -	A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
        -
        -	A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
        -
        -	"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
        -
        -	If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
        -
        -	The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
        -
        -	Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
        -
        -
        -	7. Additional Terms:
        -
        -	"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
        -
        -	When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
        -
        -	Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the
        -copyright holders of that material) supplement the terms of this License with terms:
        -
        -	    * a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
        -	    * b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
        -	    * c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
        -	    * d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
        -	    * e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
        -	    * f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
        -
        -	All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
        -
        -	If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
        -
        -	Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
        -
        -
        -	8. Termination:
        -
        -	You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
        -
        -	However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
        -
        -	Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
        -
        -	Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
        -
        -
        -	9. Acceptance Not Required for Having Copies:
        -
        -	You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
        -
        -
        -	10. Automatic Licensing of Downstream Recipients:
        -
        -	Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
        -
        -	An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
        -
        -	You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
        -
        -
        -	11. Patents:
        -
        -	A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".
        -
        -	A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
        -
        -	Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
        -
        -	In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
        -
        -	If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
        -
        -	If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
        -
        -	A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
        -
        -	Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
        -
        -
        -	12. No Surrender of Others' Freedom:
        -
        -	If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
        -
        -
        -	13. Remote Network Interaction; Use with the GNU General Public License:
        -
        -	Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph.
        -
        -	Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License.
        -
        -
        -	14. Revised Versions of this License:
        -
        -	The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
        -
        -	Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation.
        -
        -	If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
        -
        -	Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
        -
        -
        -	15. Disclaimer of Warranty:
        -
        -	THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
        -
        -
        -	16. Limitation of Liability:
        -
        -	IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
        -
        -
        -	17. Interpretation of Sections 15 and 16:
        -
        -	If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
        -
        -	END OF TERMS AND CONDITIONS
        -
        -
        -How to Apply These Terms to Your New Programs:
        -
        -If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
        -
        -To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
        -
        -    <one line to give the program's name and a brief idea of what it does.>
        -    Copyright (C) <year>  <name of author>
        -
        -    This program is free software: you can redistribute it and/or modify
        -    it under the terms of the GNU Affero General Public License as
        -    published by the Free Software Foundation, either version 3 of the
        -    License, or (at your option) any later version.
        -
        -    This program is distributed in the hope that it will be useful,
        -    but WITHOUT ANY WARRANTY; without even the implied warranty of
        -    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        -    GNU Affero General Public License for more details.
        -
        -    You should have received a copy of the GNU Affero General Public License
        -    along with this program.  If not, see <http://www.gnu.org/licenses/>.
        -
        -Also add information on how to contact you by electronic and paper mail.
        -
        -If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements.
        -
        -You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see <http://www.gnu.org/licenses/>.
        -
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/BinaryFile.pm b/vendor/naturaldocs/Modules/NaturalDocs/BinaryFile.pm
        deleted file mode 100644
        index ff9a444b1..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/BinaryFile.pm
        +++ /dev/null
        @@ -1,295 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::BinaryFile
        -#
        -###############################################################################
        -#
        -#   A package to manage Natural Docs' binary data files.
        -#
        -#   Usage:
        -#
        -#       - Only one data file can be managed with this package at a time.  You must close the file before opening another
        -#         one.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::BinaryFile;
        -
        -use vars qw(@EXPORT @ISA);
        -require Exporter;
        -@ISA = qw(Exporter);
        -
        -@EXPORT = ('BINARY_FORMAT');
        -
        -
        -###############################################################################
        -# Group: Format
        -
        -#
        -#   Topic: Standard Header
        -#
        -#   > [UInt8: BINARY_FORMAT]
        -#   > [VersionInt: app version]
        -#
        -#   The first byte is <BINARY_FORMAT>, which distinguishes binary configuration files from text ones, since Natural Docs
        -#   used to use text data files with the same name.
        -#
        -#   The next section is the version of Natural Docs that wrote the file, as defined by <NaturalDocs::Settings->AppVersion>
        -#   and written by <NaturalDocs::Version->ToBinaryFile()>.
        -#
        -
        -#
        -#   Topic: Data Types
        -#
        -#   All the integer data types are written most significant byte first, aka big endian.
        -#
        -#   An AString16 is a UInt16 followed by that many 8-bit ASCII characters.  It doesn't include a null character at the end.  Undef
        -#   strings are represented by a zero for the UInt16 and nothing following it.
        -#
        -
        -#
        -#   Constant: BINARY_FORMAT
        -#
        -#   An 8-bit constant that's used as the first byte of binary data files.  This is used so that you can easily distinguish between
        -#   binary and old-style text data files.  It's not a character that would appear in plain text files.
        -#
        -use constant BINARY_FORMAT => pack('C', 0x06);
        -# Which is ACK or acknowledge in ASCII.  Is the cool spade character in DOS displays.
        -
        -
        -###############################################################################
        -# Group: Variables
        -
        -#
        -#   handle: FH_BINARYDATAFILE
        -#
        -#   The file handle used for the data file.
        -#
        -
        -
        -#
        -#   string: currentFile
        -#
        -#   The <FileName> for the current configuration file being parsed.
        -#
        -my $currentFile;
        -
        -
        -
        -###############################################################################
        -# Group: File Functions
        -
        -
        -#
        -#   Function: OpenForReading
        -#
        -#   Opens a binary file for reading.
        -#
        -#   Parameters:
        -#
        -#       minimumVersion - The minimum version of the file format that is acceptible.  May be undef.
        -#
        -#   Returns:
        -#
        -#       The format <VersionInt> or undef if it failed.  It could fail for any of the following reasons.
        -#
        -#       - The file doesn't exist.
        -#       - The file couldn't be opened.
        -#       - The file didn't have the proper header.
        -#       - Either the application or the file was from a development release, and they're not the exact same development release.
        -#       - The file's format was less than the minimum version, if one was defined.
        -#       - The file was from a later application version than the current.
        -#
        -sub OpenForReading #(FileName file, optional VersionInt minimumVersion) => VersionInt
        -    {
        -    my ($self, $file, $minimumVersion) = @_;
        -
        -    if (defined $currentFile)
        -        {  die "Tried to open binary file " . $file . " for reading when " . $currentFile . " was already open.";  };
        -
        -    $currentFile = $file;
        -
        -    if (open(FH_BINARYDATAFILE, '<' . $currentFile))
        -        {
        -        # See if it's binary.
        -        binmode(FH_BINARYDATAFILE);
        -
        -        my $firstChar;
        -        read(FH_BINARYDATAFILE, $firstChar, 1);
        -
        -        if ($firstChar == ::BINARY_FORMAT())
        -            {
        -            my $version = NaturalDocs::Version->FromBinaryFile(\*FH_BINARYDATAFILE);
        -
        -            if (NaturalDocs::Version->CheckFileFormat($version, $minimumVersion))
        -                {  return $version;  };
        -            };
        -
        -        close(FH_BINARYDATAFILE);
        -        };
        -
        -    $currentFile = undef;
        -    return undef;
        -    };
        -
        -
        -#
        -#   Function: OpenForWriting
        -#
        -#   Opens a binary file for writing and writes the standard header.  Dies if the file cannot be opened.
        -#
        -sub OpenForWriting #(FileName file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    if (defined $currentFile)
        -        {  die "Tried to open binary file " . $file . " for writing when " . $currentFile . " was already open.";  };
        -
        -    $currentFile = $file;
        -
        -    open (FH_BINARYDATAFILE, '>' . $currentFile)
        -        or die "Couldn't save " . $file . ".\n";
        -
        -    binmode(FH_BINARYDATAFILE);
        -
        -    print FH_BINARYDATAFILE '' . ::BINARY_FORMAT();
        -    NaturalDocs::Version->ToBinaryFile(\*FH_BINARYDATAFILE, NaturalDocs::Settings->AppVersion());
        -    };
        -
        -
        -#
        -#   Function: Close
        -#
        -#   Closes the current configuration file.
        -#
        -sub Close
        -    {
        -    my $self = shift;
        -
        -    if (!$currentFile)
        -        {  die "Tried to close a binary file when one wasn't open.";  };
        -
        -    close(FH_BINARYDATAFILE);
        -    $currentFile = undef;
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Reading Functions
        -
        -
        -#
        -#   Function: GetUInt8
        -#   Reads and returns a UInt8 from the open file.
        -#
        -sub GetUInt8 # => UInt8
        -    {
        -    my $raw;
        -    read(FH_BINARYDATAFILE, $raw, 1);
        -
        -    return unpack('C', $raw);
        -    };
        -
        -#
        -#   Function: GetUInt16
        -#   Reads and returns a UInt16 from the open file.
        -#
        -sub GetUInt16 # => UInt16
        -    {
        -    my $raw;
        -    read(FH_BINARYDATAFILE, $raw, 2);
        -
        -    return unpack('n', $raw);
        -    };
        -
        -#
        -#   Function: GetUInt32
        -#   Reads and returns a UInt32 from the open file.
        -#
        -sub GetUInt32 # => UInt32
        -    {
        -    my $raw;
        -    read(FH_BINARYDATAFILE, $raw, 4);
        -
        -    return unpack('N', $raw);
        -    };
        -
        -#
        -#   Function: GetAString16
        -#   Reads and returns an AString16 from the open file.  Supports undef strings.
        -#
        -sub GetAString16 # => string
        -    {
        -    my $rawLength;
        -    read(FH_BINARYDATAFILE, $rawLength, 2);
        -    my $length = unpack('n', $rawLength);
        -
        -    if (!$length)
        -        {  return undef;  };
        -
        -    my $string;
        -    read(FH_BINARYDATAFILE, $string, $length);
        -
        -    return $string;
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Writing Functions
        -
        -
        -#
        -#   Function: WriteUInt8
        -#   Writes a UInt8 to the open file.
        -#
        -sub WriteUInt8 #(UInt8 value)
        -    {
        -    my ($self, $value) = @_;
        -    print FH_BINARYDATAFILE pack('C', $value);
        -    };
        -
        -#
        -#   Function: WriteUInt16
        -#   Writes a UInt32 to the open file.
        -#
        -sub WriteUInt16 #(UInt16 value)
        -    {
        -    my ($self, $value) = @_;
        -    print FH_BINARYDATAFILE pack('n', $value);
        -    };
        -
        -#
        -#   Function: WriteUInt32
        -#   Writes a UInt32 to the open file.
        -#
        -sub WriteUInt32 #(UInt32 value)
        -    {
        -    my ($self, $value) = @_;
        -    print FH_BINARYDATAFILE pack('N', $value);
        -    };
        -
        -#
        -#   Function: WriteAString16
        -#   Writes an AString16 to the open file.  Supports undef strings.
        -#
        -sub WriteAString16 #(string value)
        -    {
        -    my ($self, $string) = @_;
        -
        -    if (length($string))
        -        {  print FH_BINARYDATAFILE pack('nA*', length($string), $string);  }
        -    else
        -        {  print FH_BINARYDATAFILE pack('n', 0);  };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Builder.pm b/vendor/naturaldocs/Modules/NaturalDocs/Builder.pm
        deleted file mode 100644
        index e8b1cd37a..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Builder.pm
        +++ /dev/null
        @@ -1,281 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Builder
        -#
        -###############################################################################
        -#
        -#   A package that takes parsed source file and builds the output for it.
        -#
        -#   Usage and Dependencies:
        -#
        -#       - <Add()> can be called immediately.
        -#       - <OutputPackages()> and <OutputPackageOf()> can be called once all sub-packages have been registered via <Add()>.
        -#         Since this is normally done in their INIT functions, they should be available to all normal functions immediately.
        -#
        -#       - Prior to calling <Run()>, <NaturalDocs::Settings>, <NaturalDocs::Project>, <NaturalDocs::Menu>, and
        -#         <NaturalDocs::Parser> must be initialized.  <NaturalDocs::Settings->GenerateDirectoryNames()> must be called.
        -#         <NaturalDocs::SymbolTable> and <NaturalDocs::ClassHierarchy> must be initialized and fully resolved.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -
        -use strict;
        -use integer;
        -
        -use NaturalDocs::Builder::Base;
        -use NaturalDocs::Builder::HTML;
        -use NaturalDocs::Builder::FramedHTML;
        -
        -package NaturalDocs::Builder;
        -
        -
        -###############################################################################
        -# Group: Variables
        -
        -#
        -#   Array: outputPackages
        -#
        -#   An array of the output packages available for use.
        -#
        -my @outputPackages;
        -
        -
        -###############################################################################
        -# Group: Functions
        -
        -
        -#
        -#   Function: OutputPackages
        -#
        -#   Returns an arrayref of the output packages available for use.  The arrayref is not a copy of the data, so don't change it.
        -#
        -#   Add output packages to this list with the <Add()> function.
        -#
        -sub OutputPackages
        -    {  return \@outputPackages;  };
        -
        -
        -#
        -#   Function: OutputPackageOf
        -#
        -#   Returns the output package corresponding to the passed command line option, or undef if none.
        -#
        -sub OutputPackageOf #(commandLineOption)
        -    {
        -    my ($self, $commandLineOption) = @_;
        -
        -    $commandLineOption = lc($commandLineOption);
        -
        -    foreach my $package (@outputPackages)
        -        {
        -        if (lc($package->CommandLineOption()) eq $commandLineOption)
        -            {  return $package;  };
        -        };
        -
        -    return undef;
        -    };
        -
        -
        -
        -#
        -#   Function: Add
        -#
        -#   Adds an output package to those available for use.  All output packages must call this function in order to be recognized.
        -#
        -#   Parameters:
        -#
        -#       package - The package name.
        -#
        -sub Add #(package)
        -    {
        -    my ($self, $package) = @_;
        -
        -    # Output packages shouldn't register themselves more than once, so we don't need to check for it.
        -    push @outputPackages, $package;
        -    };
        -
        -
        -#
        -#   Function: Run
        -#
        -#   Runs the build process.  This must be called *every time* Natural Docs is run, regardless of whether any source files changed
        -#   or not.  Some output packages have dependencies on files outside of the source tree that need to be checked.
        -#
        -#   Since there are multiple stages to the build process, this function will handle its own status messages.  There's no need to print
        -#   "Building files..." or something similar beforehand.
        -#
        -sub Run
        -    {
        -    my ($self) = @_;
        -
        -
        -    # Determine what we're doing.
        -
        -    my $buildTargets = NaturalDocs::Settings->BuildTargets();
        -
        -    my $filesToBuild = NaturalDocs::Project->FilesToBuild();
        -    my $numberOfFilesToBuild = (scalar keys %$filesToBuild) * (scalar @$buildTargets);
        -
        -    my $filesToPurge = NaturalDocs::Project->FilesToPurge();
        -    my $numberOfFilesToPurge = (scalar keys %$filesToPurge) * (scalar @$buildTargets);
        -
        -    my $imagesToUpdate = NaturalDocs::Project->ImageFilesToUpdate();
        -    my $numberOfImagesToUpdate = (scalar keys %$imagesToUpdate) * (scalar @$buildTargets);
        -
        -    my $imagesToPurge = NaturalDocs::Project->ImageFilesToPurge();
        -    my $numberOfImagesToPurge = (scalar keys %$imagesToPurge) * (scalar @$buildTargets);
        -
        -    my %indexesToBuild;
        -    my %indexesToPurge;
        -
        -    my $currentIndexes = NaturalDocs::Menu->Indexes();
        -    my $previousIndexes = NaturalDocs::Menu->PreviousIndexes();
        -
        -    foreach my $index (keys %$currentIndexes)
        -        {
        -        if (NaturalDocs::SymbolTable->IndexChanged($index) || !exists $previousIndexes->{$index})
        -            {
        -            $indexesToBuild{$index} = 1;
        -            };
        -        };
        -
        -    # All indexes that still exist should have been deleted.
        -    foreach my $index (keys %$previousIndexes)
        -        {
        -        if (!exists $currentIndexes->{$index})
        -            {
        -            $indexesToPurge{$index} = 1;
        -            };
        -        };
        -
        -    my $numberOfIndexesToBuild = (scalar keys %indexesToBuild) * (scalar @$buildTargets);
        -    my $numberOfIndexesToPurge = (scalar keys %indexesToPurge) * (scalar @$buildTargets);
        -
        -
        -    # Start the build process
        -
        -    foreach my $buildTarget (@$buildTargets)
        -        {
        -        $buildTarget->Builder()->BeginBuild( $numberOfFilesToBuild || $numberOfFilesToPurge ||
        -                                                               $numberOfImagesToUpdate || $numberOfImagesToPurge ||
        -                                                               $numberOfIndexesToBuild || $numberOfIndexesToPurge ||
        -                                                               NaturalDocs::Menu->HasChanged() );
        -        };
        -
        -    if ($numberOfFilesToPurge)
        -        {
        -        NaturalDocs::StatusMessage->Start('Purging ' . $numberOfFilesToPurge
        -                                                          . ' file' . ($numberOfFilesToPurge > 1 ? 's' : '') . '...',
        -                                                             scalar @$buildTargets);
        -
        -        foreach my $buildTarget (@$buildTargets)
        -            {
        -            $buildTarget->Builder()->PurgeFiles($filesToPurge);
        -            NaturalDocs::StatusMessage->CompletedItem();
        -            };
        -        };
        -
        -    if ($numberOfIndexesToPurge)
        -        {
        -        NaturalDocs::StatusMessage->Start('Purging ' . $numberOfIndexesToPurge
        -                                                           . ' index' . ($numberOfIndexesToPurge > 1 ? 'es' : '') . '...',
        -                                                             scalar @$buildTargets);
        -
        -        foreach my $buildTarget (@$buildTargets)
        -            {
        -            $buildTarget->Builder()->PurgeIndexes(\%indexesToPurge);
        -            NaturalDocs::StatusMessage->CompletedItem();
        -            };
        -        };
        -
        -    if ($numberOfImagesToPurge)
        -        {
        -        NaturalDocs::StatusMessage->Start('Purging ' . $numberOfImagesToPurge
        -                                                          . ' image' . ($numberOfImagesToPurge > 1 ? 's' : '') . '...',
        -                                                             scalar @$buildTargets);
        -
        -        foreach my $buildTarget (@$buildTargets)
        -            {
        -            $buildTarget->Builder()->PurgeImages($imagesToPurge);
        -            NaturalDocs::StatusMessage->CompletedItem();
        -            };
        -        };
        -
        -    if ($numberOfFilesToBuild)
        -        {
        -        NaturalDocs::StatusMessage->Start('Building ' . $numberOfFilesToBuild
        -                                                           . ' file' . ($numberOfFilesToBuild > 1 ? 's' : '') . '...',
        -                                                             $numberOfFilesToBuild);
        -
        -        foreach my $file (keys %$filesToBuild)
        -            {
        -            my $parsedFile = NaturalDocs::Parser->ParseForBuild($file);
        -
        -            NaturalDocs::Error->OnStartBuilding($file);
        -
        -            foreach my $buildTarget (@$buildTargets)
        -                {
        -                $buildTarget->Builder()->BuildFile($file, $parsedFile);
        -                NaturalDocs::StatusMessage->CompletedItem();
        -                };
        -
        -            NaturalDocs::Error->OnEndBuilding($file);
        -            };
        -        };
        -
        -    if ($numberOfIndexesToBuild)
        -        {
        -        NaturalDocs::StatusMessage->Start('Building ' . $numberOfIndexesToBuild
        -                                                          . ' index' . ($numberOfIndexesToBuild > 1 ? 'es' : '') . '...',
        -                                                             $numberOfIndexesToBuild);
        -
        -        foreach my $index (keys %indexesToBuild)
        -            {
        -            foreach my $buildTarget (@$buildTargets)
        -                {
        -                $buildTarget->Builder()->BuildIndex($index);
        -                NaturalDocs::StatusMessage->CompletedItem();
        -                };
        -            };
        -        };
        -
        -    if ($numberOfImagesToUpdate)
        -        {
        -        NaturalDocs::StatusMessage->Start('Updating ' . $numberOfImagesToUpdate
        -                                                          . ' image' . ($numberOfImagesToUpdate > 1 ? 's' : '') . '...',
        -                                                             $numberOfImagesToUpdate);
        -
        -        foreach my $image (keys %$imagesToUpdate)
        -            {
        -            foreach my $buildTarget (@$buildTargets)
        -                {
        -                $buildTarget->Builder()->UpdateImage($image);
        -                NaturalDocs::StatusMessage->CompletedItem();
        -                };
        -            };
        -        };
        -
        -    if (NaturalDocs::Menu->HasChanged())
        -        {
        -        if (!NaturalDocs::Settings->IsQuiet())
        -            {  print "Updating menu...\n";  };
        -
        -        foreach my $buildTarget (@$buildTargets)
        -            {  $buildTarget->Builder()->UpdateMenu();  };
        -        };
        -
        -    foreach my $buildTarget (@$buildTargets)
        -        {
        -        $buildTarget->Builder()->EndBuild($numberOfFilesToBuild || $numberOfFilesToPurge ||
        -                                                           $numberOfIndexesToBuild || $numberOfIndexesToPurge ||
        -                                                           $numberOfImagesToUpdate || $numberOfImagesToPurge ||
        -                                                           NaturalDocs::Menu->HasChanged());
        -        };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Builder/Base.pm b/vendor/naturaldocs/Modules/NaturalDocs/Builder/Base.pm
        deleted file mode 100644
        index 75b3fd310..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Builder/Base.pm
        +++ /dev/null
        @@ -1,349 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Builder::Base
        -#
        -###############################################################################
        -#
        -#   A base class for all Builder output formats.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Builder::Base;
        -
        -
        -###############################################################################
        -# Group: Notes
        -
        -
        -#
        -#   Topic: Implementation
        -#
        -#   Builder packages are implemented as blessed arrayrefs, not hashrefs.  This is done for all objects in Natural Docs for
        -#   efficiency reasons.  You create members by defining constants via <NaturalDocs::DefineMembers> and using them as
        -#   indexes into the array.
        -#
        -
        -#
        -#   Topic: Function Order
        -#
        -#   The functions in the build process will always be called in the following order.
        -#
        -#   - <BeginBuild()> will always be called.
        -#   - <PurgeFiles()> will be called next only if there's files that need to be purged.
        -#   - <PurgeIndexes()> will be called next only if there's indexes that need to be purged.
        -#   - <PurgeImages()> will e called next only if there's images that need to be purged.
        -#   - <BuildFile()> will be called once for each file that needs to be built, if any.
        -#   - <BuildIndex()> will be called once for each index that changed and is part of the menu, if any.
        -#   - <UpdateImage()> will be called once for each image that needs to be updated, if any.
        -#   - <UpdateMenu()> will be called next only if the menu changed.
        -#   - <EndBuild()> will always be called.
        -#
        -
        -#
        -#   Topic: How to Approach
        -#
        -#   Here's an idea of how to approach making packages for different output types.
        -#
        -#
        -#   Multiple Output Files, Embedded Menu:
        -#
        -#       This example is for when you want to build one output file per source file, each with its own copy of the menu within it.
        -#       This is how <NaturalDocs::Builder::HTML> works.
        -#
        -#       Make sure you create a function that generates just the menu for a particular source file.  We'll need to generate menus for
        -#       both building a file from scratch and for updating the menu on an existing output file, so it's better to give it its own function.
        -#       You may want to surround it with something that can be easily detected in the output file to make replacing easier.
        -#
        -#       <BeginBuild()> isn't important.  You don't need to implement it.
        -#
        -#       Implement <PurgeFiles()> to delete the output files associated with the purged files.
        -#
        -#       Implement <PurgeIndexes()> to delete the output files associated with the purged indexes.
        -#
        -#       Implement <BuildFile()> to create an output file for the parsed source file.  Use the menu function described earlier.
        -#
        -#       Implement <BuildIndex()> to create an output file for each index.  Use the menu function described earlier for each page.
        -#
        -#       Implement <UpdateMenu()> to go through the list of unbuilt files and update their menus.  You can get the list from
        -#       <NaturalDocs::Project->UnbuiltFilesWithContent()>.  You need to open their output files, replace the menu, and save it back
        -#       to disk.  Yes, it would be simpler from a programmer's point of view to just rebuild the file completely, but that would be
        -#       _very_ inefficient since there could potentially be a _lot_ of files in this group.
        -#
        -#       Also make sure <UpdateMenu()> goes through the unchanged indexes and updates them as well.
        -#
        -#       <EndBuild()> isn't important.  You don't need to implement it.
        -#
        -#
        -#   Multiple Output Files, Menu in File:
        -#
        -#       This example is for when you want to build one output file per source file, but keep the menu in its own separate file.  This
        -#       is how <NaturalDocs::Builder::FramedHTML> works.
        -#
        -#       <BeginBuild()> isn't important.  You don't need to implement it.
        -#
        -#       Implement <PurgeFiles()> to delete the output files associated with the purged files.
        -#
        -#       Implement <PurgeIndexes()> to delete the output files associated with the purged indexes.
        -#
        -#       Implement <BuildFile()> to generate an output file from the parsed source file.
        -#
        -#       Implement <BuildIndex()> to generate an output file for each index.
        -#
        -#       Implement <UpdateMenu()> to rebuild the menu file.
        -#
        -#       <EndBuild()> isn't important.  You don't need to implement it.
        -#
        -#
        -#   Single Output File using Intermediate Files:
        -#
        -#       This example is for when you want to build one output file, such as a PDF file, but use intermediate files to handle differential
        -#       building.  This would be much like how a compiler compiles each source file into a object file, and then a linker stitches them
        -#       all together into the final executable file.
        -#
        -#       <BeginBuild()> isn't important.  You don't need to implement it.
        -#
        -#       Implement <PurgeFiles()> to delete the intermediate files associated with the purged files.
        -#
        -#       Implement <PurgeIndexes()> to delete the intermediate files associated with the purged indexes.
        -#
        -#       Implement <BuildFile()> to generate an intermediate file from the parsed source file.
        -#
        -#       Implement <BuildIndex()> to generate an intermediate file for the specified index.
        -#
        -#       Implement <UpdateMenu()> to generate the intermediate file for the menu.
        -#
        -#       Implement <EndBuild()> so that if the project changed, it stitches the intermediate files together into the final
        -#       output file.  Make sure you check the parameter because the function will be called when nothing changes too.
        -#
        -#
        -#   Single Output File using Direct Changes:
        -#
        -#       This example is for when you want to build one output file, such as a PDF file, but engineering it in such a way that you don't
        -#       need to use intermediate files.  In other words, you're able to add, delete, and modify entries directly in the output file.
        -#
        -#       Implement <BeginBuild()> so that if the project changed, it opens the output file and does anything it needs to do
        -#       to get ready for editing.
        -#
        -#       Implement <PurgeFiles()> to remove the entries associated with the purged files.
        -#
        -#       Implement <PurgeIndexes()> to remove the entries associated with the purged indexes.
        -#
        -#       Implement <BuildFile()> to add or replace a section of the output file with a new one generated from the parsed file.
        -#
        -#       Implement <BuildIndex()> to add or replace an index in the output file with a new one generated from the specified index.
        -#
        -#       Implement <EndBuild()> so that if the project changed, it saves the output file to disk.
        -#
        -#       How you handle the menu depends on how the output file references other sections of itself.  If it can do so by name, then
        -#       you can implement <UpdateMenu()> to update the menu section of the file and you're done.  If it has to reference itself
        -#       by address or offset, it gets trickier.  You should skip <UpdateMenu()> and instead rebuild the menu in <EndBuild()> if
        -#       the parameter is true.  This lets you do it whenever anything changes in a file, rather than just when the menu
        -#       visibly changes.  How you keep track of the locations and how they change is your problem.
        -#
        -
        -
        -###############################################################################
        -#
        -#   Group: Required Interface Functions
        -#
        -#   All Builder classes *must* define these functions.
        -#
        -
        -
        -#
        -#   Function: INIT
        -#
        -#   Define this function to call <NaturalDocs::Builder->Add()> so that <NaturalDocs::Builder> knows about this package.
        -#   Packages are defined this way so that new ones can be added without messing around in other code.
        -#
        -
        -
        -#
        -#   Function: CommandLineOption
        -#
        -#   Define this function to return the text that should be put in the command line after -o to use this package.  It cannot have
        -#   spaces and is not case sensitive.
        -#
        -#   For example, <NaturalDocs::Builder::HTML> returns 'html' so someone could use -o html [directory] to use that package.
        -#
        -sub CommandLineOption
        -    {
        -    NaturalDocs::Error->SoftDeath($_[0] . " didn't define CommandLineOption().");
        -    };
        -
        -
        -#
        -#   Function: BuildFile
        -#
        -#   Define this function to convert a parsed file to this package's output format.  This function will be called once for every source
        -#   file that needs to be rebuilt.  However, if a file hasn't changed since the last time Natural Docs was run, it will not be sent to
        -#   this function.  All packages must support differential build.
        -#
        -#   Parameters:
        -#
        -#       sourceFile  - The name of the source file.
        -#       parsedFile  - The parsed source file, as an arrayref of <NaturalDocs::Parser::ParsedTopic> objects.
        -#
        -sub BuildFile #(sourceFile, parsedFile)
        -    {
        -    NaturalDocs::Error->SoftDeath($_[0] . " didn't define BuildFile().");
        -    };
        -
        -
        -###############################################################################
        -#
        -#   Group: Optional Interface Functions
        -#
        -#   These functions can be implemented but packages are not required to do so.
        -#
        -
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -#   Note that this is the only function where the first parameter will be the package name, not the object itself.
        -#
        -sub New
        -    {
        -    my $package = shift;
        -
        -    my $object = [ ];
        -    bless $object, $package;
        -
        -    return $object;
        -    };
        -
        -
        -#
        -#   Function: BeginBuild
        -#
        -#   Define this function if the package needs to do anything at the beginning of the build process.  This function will be called
        -#   every time Natural Docs is run, even if the project hasn't changed.  This allows you to manage dependencies specific
        -#   to the output format that may change independently from the source tree and menu.  For example,
        -#   <NaturalDocs::Builder::HTML> needs to keep the CSS files in sync regardless of whether the source tree changed or not.
        -#
        -#   Parameters:
        -#
        -#       hasChanged - Whether the project has changed, such as source files or the menu file.  If false, nothing else is going to be
        -#                            called except <EndBuild()>.
        -#
        -sub BeginBuild #(hasChanged)
        -    {
        -    };
        -
        -
        -#
        -#   Function: EndBuild
        -#
        -#   Define this function if the package needs to do anything at the end of the build process.  This function will be called every time
        -#   Natural Docs is run, even if the project hasn't changed.  This allows you to manage dependencies specific to the output
        -#   format that may change independently from the source tree.  For example, <NaturalDocs::Builder::HTML> needs to keep the
        -#   CSS files in sync regardless of whether the source tree changed or not.
        -#
        -#   Parameters:
        -#
        -#       hasChanged - Whether the project has changed, such as source files or the menu file.  If false, the only other function that
        -#                            was called was <BeginBuild()>.
        -#
        -sub EndBuild #(hasChanged)
        -    {
        -    };
        -
        -
        -#
        -#   Function: BuildIndex
        -#
        -#   Define this function to create an index for the passed topic.  You can get the index from
        -#   <NaturalDocs::SymbolTable->Index()>.
        -#
        -#   The reason it's not passed directly to this function is because indexes may be time-consuming to create.  As such, they're
        -#   generated on demand because some output packages may choose not to implement them.
        -#
        -#   Parameters:
        -#
        -#       topic  - The <TopicType> to limit the index by.
        -#
        -sub BuildIndex #(topic)
        -    {
        -    };
        -
        -
        -#
        -#   Function: UpdateImage
        -#
        -#   Define this function to add or update the passed image in the output.
        -#
        -#   Parameters:
        -#
        -#       file - The image <FileName>
        -#
        -sub UpdateImage #(file)
        -    {
        -    };
        -
        -
        -#
        -#   Function: PurgeFiles
        -#
        -#   Define this function to make the package remove all output related to the passed files.  These files no longer have Natural Docs
        -#   content.
        -#
        -#   Parameters:
        -#
        -#       files - An existence hashref of the files to purge.
        -#
        -sub PurgeFiles #(files)
        -    {
        -    };
        -
        -
        -#
        -#   Function: PurgeIndexes
        -#
        -#   Define this function to make the package remove all output related to the passed indexes.  These indexes are no longer part
        -#   of the menu.
        -#
        -#   Parameters:
        -#
        -#       indexes  - An existence hashref of the <TopicTypes> of the indexes to purge.
        -#
        -sub PurgeIndexes #(indexes)
        -    {
        -    };
        -
        -
        -#
        -#   Function: PurgeImages
        -#
        -#   Define this function to make the package remove all output related to the passed image files.  These files are no longer used
        -#   by the documentation.
        -#
        -#   Parameters:
        -#
        -#       files - An existence hashref of the image <FileNames> to purge.
        -#
        -sub PurgeImages #(files)
        -    {
        -    };
        -
        -
        -#
        -#   Function: UpdateMenu
        -#
        -#   Define this function to make the package update the menu.  It will only be called if the menu changed.
        -#
        -sub UpdateMenu
        -    {
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Builder/FramedHTML.pm b/vendor/naturaldocs/Modules/NaturalDocs/Builder/FramedHTML.pm
        deleted file mode 100644
        index c29528a39..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Builder/FramedHTML.pm
        +++ /dev/null
        @@ -1,354 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Builder::FramedHTML
        -#
        -###############################################################################
        -#
        -#   A package that generates output in HTML with frames.
        -#
        -#   All functions are called with Package->Function() notation.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Builder::FramedHTML;
        -
        -use base 'NaturalDocs::Builder::HTMLBase';
        -
        -
        -###############################################################################
        -# Group: Implemented Interface Functions
        -
        -
        -#
        -#   Function: INIT
        -#
        -#   Registers the package with <NaturalDocs::Builder>.
        -#
        -sub INIT
        -    {
        -    NaturalDocs::Builder->Add(__PACKAGE__);
        -    };
        -
        -
        -#
        -#   Function: CommandLineOption
        -#
        -#   Returns the option to follow -o to use this package.  In this case, "html".
        -#
        -sub CommandLineOption
        -    {
        -    return 'FramedHTML';
        -    };
        -
        -
        -#
        -#   Function: BuildFile
        -#
        -#   Builds the output file from the parsed source file.
        -#
        -#   Parameters:
        -#
        -#       sourcefile       - The <FileName> of the source file.
        -#       parsedFile      - An arrayref of the source file as <NaturalDocs::Parser::ParsedTopic> objects.
        -#
        -sub BuildFile #(sourceFile, parsedFile)
        -    {
        -    my ($self, $sourceFile, $parsedFile) = @_;
        -
        -    my $outputFile = $self->OutputFileOf($sourceFile);
        -
        -
        -    # 99.99% of the time the output directory will already exist, so this will actually be more efficient.  It only won't exist
        -    # if a new file was added in a new subdirectory and this is the first time that file was ever parsed.
        -    if (!open(OUTPUTFILEHANDLE, '>' . $outputFile))
        -        {
        -        NaturalDocs::File->CreatePath( NaturalDocs::File->NoFileName($outputFile) );
        -
        -        open(OUTPUTFILEHANDLE, '>' . $outputFile)
        -            or die "Couldn't create output file " . $outputFile . "\n";
        -        };
        -
        -    binmode(OUTPUTFILEHANDLE, ':encoding(UTF-8)');
        -    my $usePrettify = (NaturalDocs::Settings->HighlightCode() || NaturalDocs::Settings->HighlightAnonymous());
        -
        -
        -    print OUTPUTFILEHANDLE
        -
        -        # IE 6 doesn't like any doctype here at all.  Add one (strict or transitional doesn't matter) and it makes the page slightly too
        -        # wide for the frame.  Mozilla and Opera handle it like champs either way because they Don't Suck(tm).
        -
        -        # '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" '
        -        # . '"http://www.w3.org/TR/REC-html40/loose.dtd">' . "\n\n"
        -
        -        '<html><head>'
        -
        -        	. '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
        -
        -            . '<title>'
        -                . $self->BuildTitle($sourceFile)
        -            . '</title>'
        -
        -            . '<link rel="stylesheet" type="text/css" href="' . $self->MakeRelativeURL($outputFile, $self->MainCSSFile(), 1) . '">'
        -
        -            . '<script language=JavaScript src="' . $self->MakeRelativeURL($outputFile, $self->MainJavaScriptFile(), 1) . '"></script>';
        -
        -            if ($usePrettify)
        -            	{
        -            	print OUTPUTFILEHANDLE
        -	            '<script language=JavaScript src="' . $self->MakeRelativeURL($outputFile, $self->PrettifyJavaScriptFile(), 1) . '">'
        -	            . '</script>';
        -            	}
        -
        -        print OUTPUTFILEHANDLE
        -        '</head><body class="FramedContentPage" onLoad="NDOnLoad();' . ($usePrettify ? 'prettyPrint();' : '') . '">'
        -            . $self->OpeningBrowserStyles()
        -
        -            . $self->StandardComments()
        -
        -            . "\n\n\n"
        -                . $self->BuildContent($sourceFile, $parsedFile)
        -            . "\n\n\n"
        -
        -            . $self->BuildToolTips()
        -
        -            . $self->ClosingBrowserStyles()
        -        . '</body></html>';
        -
        -
        -    close(OUTPUTFILEHANDLE);
        -    };
        -
        -
        -#
        -#   Function: BuildIndex
        -#
        -#   Builds an index for the passed type.
        -#
        -#   Parameters:
        -#
        -#       type  - The <TopicType> to limit the index to, or undef if none.
        -#
        -sub BuildIndex #(type)
        -    {
        -    my ($self, $type) = @_;
        -
        -    my $indexTitle = $self->IndexTitleOf($type);
        -    my $indexFile = $self->IndexFileOf($type);
        -
        -    my $startIndexPage =
        -
        -        '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" '
        -            . '"http://www.w3.org/TR/REC-html40/loose.dtd">' . "\n\n"
        -
        -        . '<html><head>'
        -
        -        	. '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
        -
        -            . '<title>';
        -
        -            if (defined NaturalDocs::Menu->Title())
        -                {  $startIndexPage .= $self->StringToHTML(NaturalDocs::Menu->Title()) . ' - ';  };
        -
        -                $startIndexPage .=
        -                $indexTitle
        -            . '</title>'
        -
        -            . '<link rel="stylesheet" type="text/css" href="' . $self->MakeRelativeURL($indexFile, $self->MainCSSFile(), 1) . '">'
        -
        -            . '<script language=JavaScript src="' . $self->MakeRelativeURL($indexFile, $self->MainJavaScriptFile(), 1) . '"></script>'
        -
        -        . '</head><body class="FramedIndexPage" onLoad="NDOnLoad()">'
        -            . $self->OpeningBrowserStyles()
        -
        -            . "\n\n\n"
        -                . $self->StandardComments()
        -            . "\n\n\n"
        -                . '<div id=Index>'
        -                    . '<div class=IPageTitle>'
        -                        . $indexTitle
        -                    . '</div>';
        -
        -
        -    my $endIndexPage =
        -
        -                    '</div><!--Index-->'
        -                . "\n\n\n"
        -
        -                . $self->ClosingBrowserStyles()
        -
        -       . '</body></html>';
        -
        -    my $startSearchResultsPage =
        -
        -        '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" '
        -            . '"http://www.w3.org/TR/REC-html40/loose.dtd">' . "\n\n"
        -
        -        . '<html><head>'
        -
        -            . '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
        -
        -            . '<link rel="stylesheet" type="text/css" href="' . $self->MakeRelativeURL($indexFile, $self->MainCSSFile(), 1) . '">'
        -
        -            . '<script language=JavaScript src="' . $self->MakeRelativeURL($indexFile, $self->MainJavaScriptFile(), 1) . '"></script>'
        -            . '<script language=JavaScript src="' . $self->MakeRelativeURL($indexFile, $self->SearchDataJavaScriptFile(), 1) . '">'
        -                . '</script>'
        -
        -        . '</head><body class="FramedSearchResultsPage" onLoad="NDOnLoad()">'
        -            . $self->OpeningBrowserStyles()
        -
        -            . "\n\n\n"
        -                . $self->StandardComments()
        -            . "\n\n\n"
        -
        -                . '<div id=Index>'
        -                    . '<div class=IPageTitle>'
        -                        . 'Search Results'
        -                    . '</div>';
        -
        -    my $endSearchResultsPage =
        -
        -                    '</div><!--Index-->'
        -                . "\n\n\n"
        -
        -                . $self->ClosingBrowserStyles()
        -
        -       . '</body></html>';
        -
        -    my $indexContent = NaturalDocs::SymbolTable->Index($type);
        -    my $pageCount = $self->BuildIndexPages($type, $indexContent, $startIndexPage, $endIndexPage,
        -                                                                  $startSearchResultsPage, $endSearchResultsPage);
        -    $self->PurgeIndexFiles($type, $indexContent, $pageCount + 1);
        -    };
        -
        -
        -#
        -#   Function: UpdateMenu
        -#
        -#   Builds the menu file.  Also generates index.html.
        -#
        -sub UpdateMenu
        -    {
        -    my $self = shift;
        -
        -    my $outputDirectory = NaturalDocs::Settings->OutputDirectoryOf($self);
        -    my $outputFile = NaturalDocs::File->JoinPaths($outputDirectory, 'menu.html');
        -
        -
        -    open(OUTPUTFILEHANDLE, '>' . $outputFile)
        -        or die "Couldn't create output file " . $outputFile . "\n";
        -
        -    binmode(OUTPUTFILEHANDLE, ':encoding(UTF-8)');
        -
        -    my $title = 'Menu';
        -    if (defined $title)
        -        {  $title .= ' - ' . NaturalDocs::Menu->Title();  };
        -
        -    $title = $self->StringToHTML($title);
        -
        -
        -    print OUTPUTFILEHANDLE
        -
        -        '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" '
        -            . '"http://www.w3.org/TR/REC-html40/loose.dtd">' . "\n\n"
        -
        -        . '<html><head>'
        -
        -          	. '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
        -
        -            . '<title>'
        -                . $title
        -            . '</title>'
        -
        -            . '<base target="Content">'
        -
        -            . '<link rel="stylesheet" type="text/css" href="' . $self->MakeRelativeURL($outputFile, $self->MainCSSFile(), 1) . '">'
        -
        -            . '<script language=JavaScript src="' . $self->MakeRelativeURL($outputFile, $self->MainJavaScriptFile(), 1) . '"></script>'
        -            . '<script language=JavaScript src="' . $self->MakeRelativeURL($outputFile, $self->SearchDataJavaScriptFile(), 1) . '">'
        -                . '</script>'
        -
        -        . '</head><body class="FramedMenuPage" onLoad="NDOnLoad()">'
        -            . $self->OpeningBrowserStyles()
        -
        -            . $self->StandardComments()
        -
        -            . "\n\n\n"
        -                . $self->BuildMenu(undef, undef)
        -            . "\n\n\n"
        -                . $self->BuildFooter(1)
        -            . "\n\n\n"
        -
        -            . $self->ClosingBrowserStyles()
        -        . '</body></html>';
        -
        -
        -    close(OUTPUTFILEHANDLE);
        -
        -
        -    # Update index.html
        -
        -    my $firstMenuEntry = $self->FindFirstFile();
        -    my $indexFile = NaturalDocs::File->JoinPaths( NaturalDocs::Settings->OutputDirectoryOf($self), 'index.html' );
        -
        -    # We have to check because it's possible that there may be no files with Natural Docs content and thus no files on the menu.
        -    if (defined $firstMenuEntry)
        -        {
        -        open(INDEXFILEHANDLE, '>' . $indexFile)
        -            or die "Couldn't create output file " . $indexFile . ".\n";
        -
        -	    binmode(OUTPUTFILEHANDLE, ':encoding(UTF-8)');
        -
        -        print INDEXFILEHANDLE
        -
        -            '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" '
        -                . '"http://www.w3.org/TR/REC-html40/frameset.dtd">'
        -
        -            . '<html>'
        -
        -                . '<head>'
        -
        -                    . '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
        -
        -                    . '<title>'
        -                        . $self->StringToHTML(NaturalDocs::Menu->Title())
        -                    . '</title>'
        -
        -                . '</head>'
        -
        -                . $self->StandardComments()
        -
        -                . '<frameset cols="185,*">'
        -                    . '<frame name=Menu src="menu.html">'
        -                    . '<frame name=Content src="'
        -                        . $self->MakeRelativeURL($indexFile, $self->OutputFileOf($firstMenuEntry->Target()), 1) . '">'
        -                . '</frameset>'
        -
        -                . '<noframes>'
        -                    . 'This documentation was designed for use with frames.  However, you can still use it by '
        -                    . '<a href="menu.html">starting from the menu page</a>.'
        -                    . "<script language=JavaScript><!--\n"
        -                        . 'location.href="menu.html";'
        -                    . "\n// --></script>"
        -                . '</noframes>'
        -
        -            . '</html>';
        -
        -        close INDEXFILEHANDLE;
        -        }
        -
        -    elsif (-e $indexFile)
        -        {
        -        unlink($indexFile);
        -        };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Builder/HTML.pm b/vendor/naturaldocs/Modules/NaturalDocs/Builder/HTML.pm
        deleted file mode 100644
        index 86bd8bf90..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Builder/HTML.pm
        +++ /dev/null
        @@ -1,414 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Builder::HTML
        -#
        -###############################################################################
        -#
        -#   A package that generates output in HTML.
        -#
        -#   All functions are called with Package->Function() notation.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Builder::HTML;
        -
        -use base 'NaturalDocs::Builder::HTMLBase';
        -
        -
        -###############################################################################
        -# Group: Implemented Interface Functions
        -
        -
        -#
        -#   Function: INIT
        -#
        -#   Registers the package with <NaturalDocs::Builder>.
        -#
        -sub INIT
        -    {
        -    NaturalDocs::Builder->Add(__PACKAGE__);
        -    };
        -
        -
        -#
        -#   Function: CommandLineOption
        -#
        -#   Returns the option to follow -o to use this package.  In this case, "html".
        -#
        -sub CommandLineOption
        -    {
        -    return 'HTML';
        -    };
        -
        -
        -#
        -#   Function: BuildFile
        -#
        -#   Builds the output file from the parsed source file.
        -#
        -#   Parameters:
        -#
        -#       sourcefile       - The <FileName> of the source file.
        -#       parsedFile      - An arrayref of the source file as <NaturalDocs::Parser::ParsedTopic> objects.
        -#
        -sub BuildFile #(sourceFile, parsedFile)
        -    {
        -    my ($self, $sourceFile, $parsedFile) = @_;
        -
        -    my $outputFile = $self->OutputFileOf($sourceFile);
        -
        -
        -    # 99.99% of the time the output directory will already exist, so this will actually be more efficient.  It only won't exist
        -    # if a new file was added in a new subdirectory and this is the first time that file was ever parsed.
        -    if (!open(OUTPUTFILEHANDLE, '>' . $outputFile))
        -        {
        -        NaturalDocs::File->CreatePath( NaturalDocs::File->NoFileName($outputFile) );
        -
        -        open(OUTPUTFILEHANDLE, '>' . $outputFile)
        -            or die "Couldn't create output file " . $outputFile . "\n";
        -        };
        -
        -    binmode(OUTPUTFILEHANDLE, ':encoding(UTF-8)');
        -    my $usePrettify = (NaturalDocs::Settings->HighlightCode() || NaturalDocs::Settings->HighlightAnonymous());
        -
        -
        -    print OUTPUTFILEHANDLE
        -
        -        '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" '
        -            . '"http://www.w3.org/TR/REC-html40/strict.dtd">' . "\n\n"
        -
        -        . '<html><head>'
        -
        -            . '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
        -
        -            . '<title>'
        -                . $self->BuildTitle($sourceFile)
        -            . '</title>'
        -
        -            . '<link rel="stylesheet" type="text/css" href="' . $self->MakeRelativeURL($outputFile, $self->MainCSSFile(), 1) . '">'
        -
        -            . '<script language=JavaScript src="' . $self->MakeRelativeURL($outputFile, $self->MainJavaScriptFile(), 1) . '">'
        -                . '</script>';
        -
        -			if ($usePrettify)
        -				{
        -				print OUTPUTFILEHANDLE
        -	            '<script language=JavaScript src="' . $self->MakeRelativeURL($outputFile, $self->PrettifyJavaScriptFile(), 1) . '">'
        -	                . '</script>';
        -                }
        -
        -            print OUTPUTFILEHANDLE
        -            '<script language=JavaScript src="' . $self->MakeRelativeURL($outputFile, $self->SearchDataJavaScriptFile(), 1) . '">'
        -                . '</script>'
        -
        -	        . '</head><body class="ContentPage" onLoad="NDOnLoad();' . ($usePrettify ? 'prettyPrint();' : '') . '">'
        -            . $self->OpeningBrowserStyles()
        -
        -            . $self->StandardComments()
        -
        -            . "\n\n\n"
        -                . $self->BuildContent($sourceFile, $parsedFile)
        -            . "\n\n\n"
        -                . $self->BuildFooter()
        -            . "\n\n\n"
        -                . $self->BuildMenu($sourceFile, undef)
        -            . "\n\n\n"
        -                . $self->BuildToolTips()
        -            . "\n\n\n"
        -                . '<div id=MSearchResultsWindow>'
        -                    . '<iframe src="" frameborder=0 name=MSearchResults id=MSearchResults></iframe>'
        -                    . '<a href="javascript:searchPanel.CloseResultsWindow()" id=MSearchResultsWindowClose>Close</a>'
        -                . '</div>'
        -            . "\n\n\n"
        -
        -            . $self->ClosingBrowserStyles()
        -        . '</body></html>';
        -
        -
        -    close(OUTPUTFILEHANDLE);
        -    };
        -
        -
        -#
        -#   Function: BuildIndex
        -#
        -#   Builds an index for the passed type.
        -#
        -#   Parameters:
        -#
        -#       type  - The <TopicType> to limit the index to, or undef if none.
        -#
        -sub BuildIndex #(type)
        -    {
        -    my ($self, $type) = @_;
        -
        -    my $indexTitle = $self->IndexTitleOf($type);
        -
        -    my $startIndexPage =
        -
        -        '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" '
        -            . '"http://www.w3.org/TR/REC-html40/strict.dtd">' . "\n\n"
        -
        -        . '<html><head>'
        -
        -            . '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
        -
        -            . '<title>'
        -                . $indexTitle;
        -
        -                if (defined NaturalDocs::Menu->Title())
        -                    {  $startIndexPage .= ' - ' . $self->StringToHTML(NaturalDocs::Menu->Title());  };
        -
        -            $startIndexPage .=
        -            '</title>'
        -
        -            . '<link rel="stylesheet" type="text/css" href="' . $self->MakeRelativeURL($self->IndexDirectory(),
        -                                                                                                                       $self->MainCSSFile()) . '">'
        -
        -            . '<script language=JavaScript src="' . $self->MakeRelativeURL($self->IndexDirectory(),
        -                                                                                                        $self->MainJavaScriptFile()) . '"></script>'
        -            . '<script language=JavaScript src="' . $self->MakeRelativeURL($self->IndexDirectory(),
        -                                                                                                        $self->SearchDataJavaScriptFile()) . '">'
        -                . '</script>'
        -
        -        . '</head><body class="IndexPage" onLoad="NDOnLoad()">'
        -            . $self->OpeningBrowserStyles()
        -
        -        . $self->StandardComments()
        -
        -        . "\n\n\n"
        -
        -        . '<div id=Index>'
        -            . '<div class=IPageTitle>'
        -                . $indexTitle
        -            . '</div>';
        -
        -    my $endIndexPage =
        -            '</div><!--Index-->'
        -
        -            . "\n\n\n"
        -                . $self->BuildFooter()
        -            . "\n\n\n"
        -                . $self->BuildMenu(undef, $type)
        -            . "\n\n\n"
        -                . '<div id=MSearchResultsWindow>'
        -                    . '<iframe src="" frameborder=0 name=MSearchResults id=MSearchResults></iframe>'
        -                    . '<a href="javascript:searchPanel.CloseResultsWindow()" id=MSearchResultsWindowClose>Close</a>'
        -                . '</div>'
        -            . "\n\n\n"
        -
        -            . $self->ClosingBrowserStyles()
        -        . '</body></html>';
        -
        -
        -    my $startSearchResultsPage =
        -
        -        '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" '
        -            . '"http://www.w3.org/TR/REC-html40/strict.dtd">' . "\n\n"
        -
        -        . '<html><head>'
        -
        -            . '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
        -
        -            . '<link rel="stylesheet" type="text/css" href="' . $self->MakeRelativeURL($self->SearchResultsDirectory(),
        -                                                                                                                       $self->MainCSSFile()) . '">'
        -
        -            . '<script language=JavaScript src="' . $self->MakeRelativeURL($self->SearchResultsDirectory(),
        -                                                                                                        $self->MainJavaScriptFile()) . '"></script>'
        -
        -        . '</head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()">'
        -            . $self->OpeningBrowserStyles()
        -
        -        . $self->StandardComments()
        -
        -        . "\n\n\n"
        -
        -        . '<div id=Index>';
        -
        -
        -    my $endSearchResultsPage =
        -        '</div>'
        -        . $self->ClosingBrowserStyles()
        -   . '</body></html>';
        -
        -    my $indexContent = NaturalDocs::SymbolTable->Index($type);
        -    my $pageCount = $self->BuildIndexPages($type, $indexContent, $startIndexPage, $endIndexPage,
        -                                                                  $startSearchResultsPage, $endSearchResultsPage);
        -    $self->PurgeIndexFiles($type, $indexContent, $pageCount + 1);
        -    };
        -
        -
        -#
        -#   Function: UpdateMenu
        -#
        -#   Updates the menu in all the output files that weren't rebuilt.  Also generates index.html.
        -#
        -sub UpdateMenu
        -    {
        -    my $self = shift;
        -
        -
        -    # Update the menu on unbuilt files.
        -
        -    my $filesToUpdate = NaturalDocs::Project->UnbuiltFilesWithContent();
        -
        -    foreach my $sourceFile (keys %$filesToUpdate)
        -        {
        -        $self->UpdateFile($sourceFile);
        -        };
        -
        -
        -    # Update the menu on unchanged index files.
        -
        -    my $indexes = NaturalDocs::Menu->Indexes();
        -
        -    foreach my $index (keys %$indexes)
        -        {
        -        if (!NaturalDocs::SymbolTable->IndexChanged($index))
        -            {
        -            $self->UpdateIndex($index);
        -            };
        -        };
        -
        -
        -    # Update index.html
        -
        -    my $firstMenuEntry = $self->FindFirstFile();
        -    my $indexFile = NaturalDocs::File->JoinPaths( NaturalDocs::Settings->OutputDirectoryOf($self), 'index.html' );
        -
        -    # We have to check because it's possible that there may be no files with Natural Docs content and thus no files on the menu.
        -    if (defined $firstMenuEntry)
        -        {
        -        open(INDEXFILEHANDLE, '>' . $indexFile)
        -            or die "Couldn't create output file " . $indexFile . ".\n";
        -
        -	    binmode(INDEXFILEHANDLE, ':encoding(UTF-8)');
        -
        -        print INDEXFILEHANDLE
        -        '<html><head>'
        -             . '<meta http-equiv="Refresh" CONTENT="0; URL='
        -                 . $self->MakeRelativeURL( NaturalDocs::File->JoinPaths( NaturalDocs::Settings->OutputDirectoryOf($self), 'index.html'),
        -                                                        $self->OutputFileOf($firstMenuEntry->Target()), 1 ) . '">'
        -        . '</head></html>';
        -
        -        close INDEXFILEHANDLE;
        -        }
        -
        -    elsif (-e $indexFile)
        -        {
        -        unlink($indexFile);
        -        };
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -
        -#
        -#   Function: UpdateFile
        -#
        -#   Updates an output file.  Replaces the menu, HTML title, and footer.  It opens the output file, makes the changes, and saves it
        -#   back to disk, which is much quicker than rebuilding the file from scratch if these were the only things that changed.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The source <FileName>.
        -#
        -#   Dependencies:
        -#
        -#       - Requires <Builder::BuildMenu()> to surround its content with the exact strings "<div id=Menu>" and "</div><!--Menu-->".
        -#       - Requires <Builder::BuildFooter()> to surround its content with the exact strings "<div id=Footer>" and
        -#         "</div><!--Footer-->".
        -#
        -sub UpdateFile #(sourceFile)
        -    {
        -    my ($self, $sourceFile) = @_;
        -
        -    my $outputFile = $self->OutputFileOf($sourceFile);
        -
        -    if (open(OUTPUTFILEHANDLE, '<' . $outputFile))
        -        {
        -        my $content;
        -
        -	    binmode(OUTPUTFILEHANDLE, ':encoding(UTF-8)');
        -        read(OUTPUTFILEHANDLE, $content, -s OUTPUTFILEHANDLE);
        -        close(OUTPUTFILEHANDLE);
        -
        -
        -        $content =~ s{<title>[^<]*<\/title>}{'<title>' . $self->BuildTitle($sourceFile) . '</title>'}e;
        -
        -        $content =~ s/<div id=Menu>.*?<\/div><!--Menu-->/$self->BuildMenu($sourceFile, undef)/es;
        -
        -        $content =~ s/<div id=Footer>.*?<\/div><!--Footer-->/$self->BuildFooter()/e;
        -
        -
        -        open(OUTPUTFILEHANDLE, '>' . $outputFile);
        -	    binmode(OUTPUTFILEHANDLE, ':encoding(UTF-8)');
        -        print OUTPUTFILEHANDLE $content;
        -        close(OUTPUTFILEHANDLE);
        -        };
        -    };
        -
        -
        -#
        -#   Function: UpdateIndex
        -#
        -#   Updates an index's output file.  Replaces the menu and footer.  It opens the output file, makes the changes, and saves it
        -#   back to disk, which is much quicker than rebuilding the file from scratch if these were the only things that changed.
        -#
        -#   Parameters:
        -#
        -#       type - The index <TopicType>, or undef if none.
        -#
        -sub UpdateIndex #(type)
        -    {
        -    my ($self, $type) = @_;
        -
        -    my $page = 1;
        -
        -    my $outputFile = $self->IndexFileOf($type, $page);
        -
        -    my $newMenu = $self->BuildMenu(undef, $type);
        -    my $newFooter = $self->BuildFooter();
        -
        -    while (-e $outputFile)
        -        {
        -        open(OUTPUTFILEHANDLE, '<' . $outputFile)
        -            or die "Couldn't open output file " . $outputFile . ".\n";
        -
        -        my $content;
        -
        -	    binmode(OUTPUTFILEHANDLE, ':encoding(UTF-8)');
        -        read(OUTPUTFILEHANDLE, $content, -s OUTPUTFILEHANDLE);
        -        close(OUTPUTFILEHANDLE);
        -
        -
        -        $content =~ s/<div id=Menu>.*?<\/div><!--Menu-->/$newMenu/es;
        -
        -        $content =~ s/<div id=Footer>.*<\/div><!--Footer-->/$newFooter/e;
        -
        -
        -        open(OUTPUTFILEHANDLE, '>' . $outputFile)
        -            or die "Couldn't save output file " . $outputFile . ".\n";
        -
        -	    binmode(OUTPUTFILEHANDLE, ':encoding(UTF-8)');
        -        print OUTPUTFILEHANDLE $content;
        -        close(OUTPUTFILEHANDLE);
        -
        -        $page++;
        -        $outputFile = $self->IndexFileOf($type, $page);
        -        };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Builder/HTMLBase.pm b/vendor/naturaldocs/Modules/NaturalDocs/Builder/HTMLBase.pm
        deleted file mode 100644
        index 9d7dab0b0..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Builder/HTMLBase.pm
        +++ /dev/null
        @@ -1,3745 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Builder::HTMLBase
        -#
        -###############################################################################
        -#
        -#   A base package for all the shared functionality in <NaturalDocs::Builder::HTML> and
        -#   <NaturalDocs::Builder::FramedHTML>.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -
        -use Tie::RefHash;
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Builder::HTMLBase;
        -
        -use base 'NaturalDocs::Builder::Base';
        -
        -use NaturalDocs::DefineMembers 'MADE_EMPTY_SEARCH_RESULTS_PAGE', 'MadeEmptySearchResultsPage()',
        -                                                 'SetMadeEmptySearchResultsPage()';
        -
        -
        -
        -###############################################################################
        -# Group: Object Variables
        -
        -
        -#
        -#   Constants: Members
        -#
        -#   The object is implemented as a blessed arrayref, with the follow constants as indexes.
        -#
        -#   MADE_EMPTY_SEARCH_RESULTS_PAGE - Whether the search results page for searches with no results was generated.
        -#
        -
        -#
        -#   Constants: NDMarkupToHTML Styles
        -#
        -#   These are the styles used with <NDMarkupToHTML()>.
        -#
        -#   NDMARKUPTOHTML_GENERAL - General style.
        -#   NDMARKUPTOHTML_SUMMARY - For summaries.
        -#   NDMARKUPTOHTML_TOOLTIP - For tooltips.
        -#
        -use constant NDMARKUPTOHTML_GENERAL => undef;
        -use constant NDMARKUPTOHTML_SUMMARY => 1;
        -use constant NDMARKUPTOHTML_TOOLTIP => 2;
        -
        -
        -
        -###############################################################################
        -# Group: Package Variables
        -# These variables are shared by all instances of the package so don't change them.
        -
        -
        -#
        -#   handle: FH_CSS_FILE
        -#
        -#   The file handle to use when updating CSS files.
        -#
        -
        -
        -#
        -#   Hash: abbreviations
        -#
        -#   An existence hash of acceptable abbreviations.  These are words that <AddDoubleSpaces()> won't put a second space
        -#   after when followed by period-whitespace-capital letter.  Yes, this is seriously over-engineered.
        -#
        -my %abbreviations = ( mr => 1, mrs => 1, ms => 1, dr => 1,
        -                                  rev => 1, fr => 1, 'i.e' => 1,
        -                                  maj => 1, gen => 1, pres => 1, sen => 1, rep => 1,
        -                                  n => 1, s => 1, e => 1, w => 1, ne => 1, se => 1, nw => 1, sw => 1 );
        -
        -#
        -#   array: indexHeadings
        -#
        -#   An array of the headings of all the index sections.  First is for symbols, second for numbers, and the rest for each letter.
        -#
        -my @indexHeadings = ( '$#!', '0-9', 'A' .. 'Z' );
        -
        -#
        -#   array: indexAnchors
        -#
        -#   An array of the HTML anchors of all the index sections.  First is for symbols, second for numbers, and the rest for each letter.
        -#
        -my @indexAnchors = ( 'Symbols', 'Numbers', 'A' .. 'Z' );
        -
        -#
        -#   array: searchExtensions
        -#
        -#   An array of the search file name extensions for all the index sections.  First is for symbols, second for numbers, and the rest
        -#   for each letter.
        -#
        -my @searchExtensions = ( 'Symbols', 'Numbers', 'A' .. 'Z' );
        -
        -#
        -#   bool: saidUpdatingCSSFile
        -#
        -#   Whether the status message "Updating CSS file..." has been displayed.  We only want to print it once, no matter how many
        -#   HTML-based targets we are building.
        -#
        -my $saidUpdatingCSSFile;
        -
        -#
        -#   constant: ADD_HIDDEN_BREAKS
        -#
        -#   Just a synonym for "1" so that setting the flag on <StringToHTML()> is clearer in the calling code.
        -#
        -use constant ADD_HIDDEN_BREAKS => 1;
        -
        -
        -###############################################################################
        -# Group: ToolTip Package Variables
        -#
        -#   These variables are for the tooltip generation functions only.  Since they're reset on every call to <BuildContent()> and
        -#   <BuildIndexSections()>, and are only used by them and their support functions, they can be shared by all instances of the
        -#   package.
        -
        -#
        -#   int: tooltipLinkNumber
        -#
        -#   A number used as part of the ID for each link that has a tooltip.  Should be incremented whenever one is made.
        -#
        -my $tooltipLinkNumber;
        -
        -#
        -#   int: tooltipNumber
        -#
        -#   A number used as part of the ID for each tooltip.  Should be incremented whenever one is made.
        -#
        -my $tooltipNumber;
        -
        -#
        -#   hash: tooltipSymbolsToNumbers
        -#
        -#   A hash that maps the tooltip symbols to their assigned numbers.
        -#
        -my %tooltipSymbolsToNumbers;
        -
        -#
        -#   string: tooltipHTML
        -#
        -#   The generated tooltip HTML.
        -#
        -my $tooltipHTML;
        -
        -
        -###############################################################################
        -# Group: Menu Package Variables
        -#
        -#   These variables are for the menu generation functions only.  Since they're reset on every call to <BuildMenu()> and are
        -#   only used by it and its support functions, they can be shared by all instances of the package.
        -#
        -
        -
        -#
        -#   hash: prebuiltMenus
        -#
        -#   A hash that maps output directonies to menu HTML already built for it.  There will be no selection or JavaScript in the menus.
        -#
        -my %prebuiltMenus;
        -
        -
        -#
        -#   bool: menuNumbersAndLengthsDone
        -#
        -#   Set when the variables that only need to be calculated for the menu once are done.  This includes <menuGroupNumber>,
        -#   <menuLength>, <menuGroupLengths>, and <menuGroupNumbers>, and <menuRootLength>.
        -#
        -my $menuNumbersAndLengthsDone;
        -
        -
        -#
        -#   int: menuGroupNumber
        -#
        -#   The current menu group number.  Each time a group is created, this is incremented so that each one will be unique.
        -#
        -my $menuGroupNumber;
        -
        -
        -#
        -#   int: menuLength
        -#
        -#   The length of the entire menu, fully expanded.  The value is computed from the <Menu Length Constants>.
        -#
        -my $menuLength;
        -
        -
        -#
        -#   hash: menuGroupLengths
        -#
        -#   A hash of the length of each group, *not* including any subgroup contents.  The keys are references to each groups'
        -#   <NaturalDocs::Menu::Entry> object, and the values are their lengths computed from the <Menu Length Constants>.
        -#
        -my %menuGroupLengths;
        -tie %menuGroupLengths, 'Tie::RefHash';
        -
        -
        -#
        -#   hash: menuGroupNumbers
        -#
        -#   A hash of the number of each group, as managed by <menuGroupNumber>.  The keys are references to each groups'
        -#   <NaturalDocs::Menu::Entry> object, and the values are the number.
        -#
        -my %menuGroupNumbers;
        -tie %menuGroupNumbers, 'Tie::RefHash';
        -
        -
        -#
        -#   int: menuRootLength
        -#
        -#   The length of the top-level menu entries without expansion.  The value is computed from the <Menu Length Constants>.
        -#
        -my $menuRootLength;
        -
        -
        -#
        -#   constants: Menu Length Constants
        -#
        -#   Constants used to approximate the lengths of the menu or its groups.
        -#
        -#   MENU_TITLE_LENGTH       - The length of the title.
        -#   MENU_SUBTITLE_LENGTH - The length of the subtitle.
        -#   MENU_FILE_LENGTH         - The length of one file entry.
        -#   MENU_GROUP_LENGTH     - The length of one group entry.
        -#   MENU_TEXT_LENGTH        - The length of one text entry.
        -#   MENU_LINK_LENGTH        - The length of one link entry.
        -#
        -#   MENU_LENGTH_LIMIT    - The limit of the menu's length.  If the total length surpasses this limit, groups that aren't required
        -#                                       to be open to show the selection will default to closed on browsers that support it.
        -#
        -use constant MENU_TITLE_LENGTH => 3;
        -use constant MENU_SUBTITLE_LENGTH => 1;
        -use constant MENU_FILE_LENGTH => 1;
        -use constant MENU_GROUP_LENGTH => 2; # because it's a line and a blank space
        -use constant MENU_TEXT_LENGTH => 1;
        -use constant MENU_LINK_LENGTH => 1;
        -use constant MENU_INDEX_LENGTH => 1;
        -
        -use constant MENU_LENGTH_LIMIT => 35;
        -
        -
        -###############################################################################
        -# Group: Image Package Variables
        -#
        -#   These variables are for the image generation functions only.  Since they're reset on every call to <BuildContent()>,
        -#   and are only used by it and its support functions, they can be shared by all instances of thepackage.
        -
        -
        -#
        -#   var: imageAnchorNumber
        -#   Incremented for each image link in the file that requires an anchor.
        -#
        -my $imageAnchorNumber;
        -
        -
        -#
        -#   var: imageContent
        -#
        -#   The actual embedded image HTML for all image links.  When generating an image link, the link HTML is returned and
        -#   the HTML for the target image is added here.  Periodically, such as after the end of the paragraph, this content should
        -#   be added to the page and the variable set to undef.
        -#
        -my $imageContent;
        -
        -
        -
        -###############################################################################
        -# Group: Search Package Variables
        -#
        -#   These variables are for the search generation functions only.  Since they're reset on every call to <BuildIndexSections()> and
        -#   are only used by them and their support functions, they can be shared by all instances of the package.
        -
        -
        -#
        -#   hash: searchResultIDs
        -#
        -#   A hash mapping lowercase-only search result IDs to the number of times they've been used.  This is to work around an IE
        -#   bug where it won't correctly reference IDs if they differ only in case.
        -#
        -my %searchResultIDs;
        -
        -
        -
        -###############################################################################
        -# Group: Object Functions
        -
        -
        -#
        -#   Function: New
        -#   Creates and returns a new object.
        -#
        -sub New
        -    {
        -    my $class = shift;
        -
        -    my $object = $class->SUPER::New();
        -    $object->SetMadeEmptySearchResultsPage(0);
        -
        -    return $object;
        -    };
        -
        -
        -# Function: MadeEmptySearchResultsPage
        -# Returns whether the empty search results page was created or not.
        -
        -# Function: SetMadeEmptySearchResultsPage
        -# Sets whether the empty search results page was created or not.
        -
        -
        -
        -###############################################################################
        -# Group: Implemented Interface Functions
        -#
        -#   The behavior of these functions is shared between HTML output formats.
        -#
        -
        -
        -#
        -#   Function: UpdateImage
        -#
        -#   Define this function to add or update the passed image in the output.
        -#
        -#   Parameters:
        -#
        -#       file - The image <FileName>
        -#
        -sub UpdateImage #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    my $outputFile = $self->OutputImageOf($file);
        -    my $outputDirectory = NaturalDocs::File->NoFileName($outputFile);
        -
        -    if (!-d $outputDirectory)
        -        {  NaturalDocs::File->CreatePath($outputDirectory);  };
        -
        -    NaturalDocs::File->Copy($file, $outputFile);
        -    };
        -
        -
        -#
        -#   Function: PurgeFiles
        -#
        -#   Deletes the output files associated with the purged source files.
        -#
        -sub PurgeFiles #(filesToPurge)
        -    {
        -    my ($self, $filesToPurge) = @_;
        -
        -    # Combine directories into a hash to remove duplicate work.
        -    my %directoriesToPurge;
        -
        -    foreach my $file (keys %$filesToPurge)
        -        {
        -        # It's possible that there may be files there that aren't in a valid input directory anymore.  They won't generate an output
        -        # file name so we need to check for undef.
        -        my $outputFile = $self->OutputFileOf($file);
        -        if (defined $outputFile)
        -            {
        -            unlink($outputFile);
        -            $directoriesToPurge{ NaturalDocs::File->NoFileName($outputFile) } = 1;
        -            };
        -        };
        -
        -    foreach my $directory (keys %directoriesToPurge)
        -        {
        -        NaturalDocs::File->RemoveEmptyTree($directory, NaturalDocs::Settings->OutputDirectoryOf($self));
        -        };
        -    };
        -
        -
        -#
        -#   Function: PurgeIndexes
        -#
        -#   Deletes the output files associated with the purged source files.
        -#
        -#   Parameters:
        -#
        -#       indexes  - An existence hashref of the index types to purge.  The keys are the <TopicTypes> or * for the general index.
        -#
        -sub PurgeIndexes #(indexes)
        -    {
        -    my ($self, $indexes) = @_;
        -
        -    foreach my $index (keys %$indexes)
        -        {
        -        $self->PurgeIndexFiles($index, undef, undef);
        -        };
        -    };
        -
        -
        -#
        -#   Function: PurgeImages
        -#
        -#   Define this function to make the package remove all output related to the passed image files.  These files are no longer used
        -#   by the documentation.
        -#
        -#   Parameters:
        -#
        -#       files - An existence hashref of the image <FileNames> to purge.
        -#
        -sub PurgeImages #(files)
        -    {
        -    my ($self, $filesToPurge) = @_;
        -
        -    # Combine directories into a hash to remove duplicate work.
        -    my %directoriesToPurge;
        -
        -    foreach my $file (keys %$filesToPurge)
        -        {
        -        # It's possible that there may be files there that aren't in a valid input directory anymore.  They won't generate an output
        -        # file name so we need to check for undef.
        -        my $outputFile = $self->OutputImageOf($file);
        -        if (defined $outputFile)
        -            {
        -            unlink($outputFile);
        -            $directoriesToPurge{ NaturalDocs::File->NoFileName($outputFile) } = 1;
        -            };
        -        };
        -
        -    foreach my $directory (keys %directoriesToPurge)
        -        {
        -        NaturalDocs::File->RemoveEmptyTree($directory, NaturalDocs::Settings->OutputDirectoryOf($self));
        -        };
        -    };
        -
        -
        -#
        -#   Function: BeginBuild
        -#
        -#   Creates the necessary subdirectories in the output directory.
        -#
        -sub BeginBuild #(hasChanged)
        -    {
        -    my ($self, $hasChanged) = @_;
        -
        -    foreach my $directory ( $self->JavaScriptDirectory(), $self->CSSDirectory(), $self->IndexDirectory(),
        -                                       $self->SearchResultsDirectory() )
        -        {
        -        if (!-d $directory)
        -            {  NaturalDocs::File->CreatePath($directory);  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: EndBuild
        -#
        -#   Synchronizes the projects CSS and JavaScript files.  Also generates the search data JavaScript file.
        -#
        -sub EndBuild #(hasChanged)
        -    {
        -    my ($self, $hasChanged) = @_;
        -
        -
        -    # Update the style sheets.
        -
        -    my $styles = NaturalDocs::Settings->Styles();
        -    my $changed;
        -
        -    my $cssDirectory = $self->CSSDirectory();
        -    my $mainCSSFile = $self->MainCSSFile();
        -
        -    for (my $i = 0; $i < scalar @$styles; $i++)
        -        {
        -        my $outputCSSFile;
        -
        -        if (scalar @$styles == 1)
        -            {  $outputCSSFile = $mainCSSFile;  }
        -        else
        -            {  $outputCSSFile = NaturalDocs::File->JoinPaths($cssDirectory, ($i + 1) . '.css');  };
        -
        -
        -        my $masterCSSFile = NaturalDocs::File->JoinPaths( NaturalDocs::Settings->ProjectDirectory(), $styles->[$i] . '.css' );
        -
        -        if (! -e $masterCSSFile)
        -            {  $masterCSSFile = NaturalDocs::File->JoinPaths( NaturalDocs::Settings->StyleDirectory(), $styles->[$i] . '.css' );  };
        -
        -        # We check both the date and the size in case the user switches between two styles which just happen to have the same
        -        # date.  Should rarely happen, but it might.
        -        if (! -e $outputCSSFile ||
        -            (stat($masterCSSFile))[9] != (stat($outputCSSFile))[9] ||
        -             -s $masterCSSFile != -s $outputCSSFile)
        -            {
        -            if (!NaturalDocs::Settings->IsQuiet() && !$saidUpdatingCSSFile)
        -                {
        -                print "Updating CSS file...\n";
        -                $saidUpdatingCSSFile = 1;
        -                };
        -
        -            NaturalDocs::File->Copy($masterCSSFile, $outputCSSFile);
        -
        -            $changed = 1;
        -            };
        -        };
        -
        -
        -    my $deleteFrom;
        -
        -    if (scalar @$styles == 1)
        -        {  $deleteFrom = 1;  }
        -    else
        -        {  $deleteFrom = scalar @$styles + 1;  };
        -
        -    for (;;)
        -        {
        -        my $file = NaturalDocs::File->JoinPaths($cssDirectory, $deleteFrom . '.css');
        -
        -        if (! -e $file)
        -            {  last;  };
        -
        -        unlink ($file);
        -        $deleteFrom++;
        -
        -        $changed = 1;
        -        };
        -
        -
        -    if ($changed)
        -        {
        -        if (scalar @$styles > 1)
        -            {
        -            open(FH_CSS_FILE, '>' . $mainCSSFile);
        -		    binmode(FH_CSS_FILE, ':encoding(UTF-8)');
        -
        -            for (my $i = 0; $i < scalar @$styles; $i++)
        -                {
        -                print FH_CSS_FILE '@import URL("' . ($i + 1) . '.css");' . "\n";
        -                };
        -
        -            close(FH_CSS_FILE);
        -            };
        -        };
        -
        -
        -
        -    # Update the JavaScript files
        -
        -    my $jsMaster = NaturalDocs::File->JoinPaths( NaturalDocs::Settings->JavaScriptDirectory(), 'NaturalDocs.js' );
        -    my $jsOutput = $self->MainJavaScriptFile();
        -
        -    # We check both the date and the size in case the user switches between two styles which just happen to have the same
        -    # date.  Should rarely happen, but it might.
        -    if (! -e $jsOutput ||
        -        (stat($jsMaster))[9] != (stat($jsOutput))[9] ||
        -         -s $jsMaster != -s $jsOutput)
        -        {
        -        NaturalDocs::File->Copy($jsMaster, $jsOutput);
        -        };
        -
        -
        -    my $prettifyOutput = $self->PrettifyJavaScriptFile();
        -
        -    if (NaturalDocs::Settings->HighlightCode() || NaturalDocs::Settings->HighlightAnonymous())
        -    	{
        -	    my $prettifyMaster = NaturalDocs::File->JoinPaths( NaturalDocs::Settings->JavaScriptDirectory(), 'GooglePrettify.js' );
        -
        -	    # We check both the date and the size in case the user switches between two styles which just happen to have the same
        -	    # date.  Should rarely happen, but it might.
        -	    if (! -e $prettifyOutput ||
        -	        (stat($prettifyMaster))[9] != (stat($prettifyOutput))[9] ||
        -	         -s $prettifyMaster != -s $prettifyOutput)
        -	        {
        -	        NaturalDocs::File->Copy($prettifyMaster, $prettifyOutput);
        -	        };
        -	    }
        -	elsif (-e $prettifyOutput)
        -		{
        -		unlink $prettifyOutput;
        -		}
        -
        -
        -    my @indexes = keys %{NaturalDocs::Menu->Indexes()};
        -
        -    open(FH_INDEXINFOJS, '>' . NaturalDocs::File->JoinPaths( $self->JavaScriptDirectory(), 'searchdata.js'));
        -    binmode(FH_INDEXINFOJS, ':encoding(UTF-8)');
        -
        -    print FH_INDEXINFOJS
        -    "var indexSectionsWithContent = {\n";
        -
        -    for (my $i = 0; $i < scalar @indexes; $i++)
        -        {
        -        if ($i != 0)
        -            {  print FH_INDEXINFOJS ",\n";  };
        -
        -        print FH_INDEXINFOJS '   "' . NaturalDocs::Topics->NameOfType($indexes[$i], 1, 1) . "\": {\n";
        -
        -        my $content = NaturalDocs::SymbolTable->IndexSectionsWithContent($indexes[$i]);
        -        for (my $contentIndex = 0; $contentIndex < 28; $contentIndex++)
        -            {
        -            if ($contentIndex != 0)
        -                {  print FH_INDEXINFOJS ",\n";  };
        -
        -            print FH_INDEXINFOJS '      "' . $searchExtensions[$contentIndex] . '": ' . ($content->[$contentIndex] ? 'true' : 'false');
        -            };
        -
        -        print FH_INDEXINFOJS "\n      }";
        -        };
        -
        -    print FH_INDEXINFOJS
        -    "\n   }";
        -
        -    close(FH_INDEXINFOJS);
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Section Functions
        -
        -
        -#
        -#   Function: BuildTitle
        -#
        -#   Builds and returns the HTML page title of a file.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The source <FileName> to build the title of.
        -#
        -#   Returns:
        -#
        -#       The source file's title in HTML.
        -#
        -sub BuildTitle #(sourceFile)
        -    {
        -    my ($self, $sourceFile) = @_;
        -
        -    # If we have a menu title, the page title is [menu title] - [file title].  Otherwise it is just [file title].
        -
        -    my $title = NaturalDocs::Project->DefaultMenuTitleOf($sourceFile);
        -
        -    my $menuTitle = NaturalDocs::Menu->Title();
        -    if (defined $menuTitle && $menuTitle ne $title)
        -        {  $title .= ' - ' . $menuTitle;  };
        -
        -    $title = $self->StringToHTML($title);
        -
        -    return $title;
        -    };
        -
        -#
        -#   Function: BuildMenu
        -#
        -#   Builds and returns the side menu of a file.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The source <FileName> to use if you're looking for a source file.
        -#       indexType - The index <TopicType> to use if you're looking for an index.
        -#
        -#       Both sourceFile and indexType may be undef.
        -#
        -#   Returns:
        -#
        -#       The side menu in HTML.
        -#
        -#   Dependencies:
        -#
        -#       - <Builder::HTML::UpdateFile()> and <Builder::HTML::UpdateIndex()> require this section to be surrounded with the exact
        -#         strings "<div id=Menu>" and "</div><!--Menu-->".
        -#       - This function depends on the way <BuildMenuSegment()> formats file and index entries.
        -#
        -sub BuildMenu #(FileName sourceFile, TopicType indexType) -> string htmlMenu
        -    {
        -    my ($self, $sourceFile, $indexType) = @_;
        -
        -    if (!$menuNumbersAndLengthsDone)
        -        {
        -        $menuGroupNumber = 1;
        -        $menuLength = 0;
        -        %menuGroupLengths = ( );
        -        %menuGroupNumbers = ( );
        -        $menuRootLength = 0;
        -        };
        -
        -    my $outputDirectory;
        -
        -    if ($sourceFile)
        -        {  $outputDirectory = NaturalDocs::File->NoFileName( $self->OutputFileOf($sourceFile) );  }
        -    elsif ($indexType)
        -        {  $outputDirectory = NaturalDocs::File->NoFileName( $self->IndexFileOf($indexType) );  }
        -    else
        -        {  $outputDirectory = NaturalDocs::Settings->OutputDirectoryOf($self);  };
        -
        -
        -    # Comment needed for UpdateFile().
        -    my $output = '<div id=Menu>';
        -
        -
        -    if (!exists $prebuiltMenus{$outputDirectory})
        -        {
        -        my $segmentOutput;
        -
        -        ($segmentOutput, $menuRootLength) =
        -            $self->BuildMenuSegment($outputDirectory, NaturalDocs::Menu->Content(), 1);
        -
        -        my $titleOutput;
        -
        -        my $menuTitle = NaturalDocs::Menu->Title();
        -        if (defined $menuTitle)
        -            {
        -            if (!$menuNumbersAndLengthsDone)
        -                {  $menuLength += MENU_TITLE_LENGTH;  };
        -
        -            $menuRootLength += MENU_TITLE_LENGTH;
        -
        -            $titleOutput .=
        -            '<div class=MTitle>'
        -                . $self->StringToHTML($menuTitle);
        -
        -            my $menuSubTitle = NaturalDocs::Menu->SubTitle();
        -            if (defined $menuSubTitle)
        -                {
        -                if (!$menuNumbersAndLengthsDone)
        -                    {  $menuLength += MENU_SUBTITLE_LENGTH;  };
        -
        -                $menuRootLength += MENU_SUBTITLE_LENGTH;
        -
        -                $titleOutput .=
        -                '<div class=MSubTitle>'
        -                    . $self->StringToHTML($menuSubTitle)
        -                . '</div>';
        -                };
        -
        -            $titleOutput .=
        -            '</div>';
        -            };
        -
        -        my $searchOutput;
        -
        -        if (scalar keys %{NaturalDocs::Menu->Indexes()})
        -            {
        -            $searchOutput =
        -            '<script type="text/javascript"><!--' . "\n"
        -                . 'var searchPanel = new SearchPanel("searchPanel", "' . $self->CommandLineOption() . '", '
        -                    . '"' . $self->MakeRelativeURL($outputDirectory, $self->SearchResultsDirectory()) . '");' . "\n"
        -            . '--></script>'
        -
        -            . '<div id=MSearchPanel class=MSearchPanelInactive>'
        -                . '<input type=text id=MSearchField value=Search '
        -                    . 'onFocus="searchPanel.OnSearchFieldFocus(true)" onBlur="searchPanel.OnSearchFieldFocus(false)" '
        -                    . 'onKeyUp="searchPanel.OnSearchFieldChange()">'
        -                . '<select id=MSearchType '
        -                    . 'onFocus="searchPanel.OnSearchTypeFocus(true)" onBlur="searchPanel.OnSearchTypeFocus(false)" '
        -                    . 'onChange="searchPanel.OnSearchTypeChange()">';
        -
        -                my @indexes = keys %{NaturalDocs::Menu->Indexes()};
        -                @indexes = sort
        -                    {
        -                    if ($a eq ::TOPIC_GENERAL())  {  return -1;  }
        -                    elsif ($b eq ::TOPIC_GENERAL())  {  return 1;  }
        -                    else  {  return (NaturalDocs::Topics->NameOfType($a, 1) cmp NaturalDocs::Topics->NameOfType($b, 1))  };
        -                    }  @indexes;
        -
        -                foreach my $index (@indexes)
        -                    {
        -                    my ($name, $extra);
        -                    if ($index eq ::TOPIC_GENERAL())
        -                        {
        -                        $name = 'Everything';
        -                        $extra = ' id=MSearchEverything selected ';
        -                        }
        -                    else
        -                        {  $name = $self->ConvertAmpChars(NaturalDocs::Topics->NameOfType($index, 1));  }
        -
        -                    $searchOutput .=
        -                    '<option ' . $extra . 'value="' . NaturalDocs::Topics->NameOfType($index, 1, 1) . '">'
        -                        . $name
        -                    . '</option>';
        -                    };
        -
        -                $searchOutput .=
        -                '</select>'
        -            . '</div>';
        -            };
        -
        -        $prebuiltMenus{$outputDirectory} = $titleOutput . $segmentOutput . $searchOutput;
        -        $output .= $titleOutput . $segmentOutput . $searchOutput;
        -        }
        -    else
        -        {  $output .= $prebuiltMenus{$outputDirectory};  };
        -
        -
        -    # Highlight the menu selection.
        -
        -    if ($sourceFile)
        -        {
        -        # Dependency: This depends on how BuildMenuSegment() formats file entries.
        -        my $outputFile = $self->OutputFileOf($sourceFile);
        -        my $tag = '<div class=MFile><a href="' . $self->MakeRelativeURL($outputDirectory, $outputFile) . '">';
        -        my $tagIndex = index($output, $tag);
        -
        -        if ($tagIndex != -1)
        -            {
        -            my $endIndex = index($output, '</a>', $tagIndex);
        -
        -            substr($output, $endIndex, 4, '');
        -            substr($output, $tagIndex, length($tag), '<div class=MFile id=MSelected>');
        -            };
        -        }
        -    elsif ($indexType)
        -        {
        -        # Dependency: This depends on how BuildMenuSegment() formats index entries.
        -        my $outputFile = $self->IndexFileOf($indexType);
        -        my $tag = '<div class=MIndex><a href="' . $self->MakeRelativeURL($outputDirectory, $outputFile) . '">';
        -        my $tagIndex = index($output, $tag);
        -
        -        if ($tagIndex != -1)
        -            {
        -            my $endIndex = index($output, '</a>', $tagIndex);
        -
        -            substr($output, $endIndex, 4, '');
        -            substr($output, $tagIndex, length($tag), '<div class=MIndex id=MSelected>');
        -            };
        -        };
        -
        -
        -    # If the completely expanded menu is too long, collapse all the groups that aren't in the selection hierarchy or near the
        -    # selection.  By doing this instead of having them default to closed via CSS, any browser that doesn't support changing this at
        -    # runtime will keep the menu entirely open so that its still usable.
        -
        -    if ($menuLength > MENU_LENGTH_LIMIT())
        -        {
        -        my $menuSelectionHierarchy = $self->GetMenuSelectionHierarchy($sourceFile, $indexType);
        -
        -        my $toExpand = $self->ExpandMenu($sourceFile, $indexType, $menuSelectionHierarchy, $menuRootLength);
        -
        -        $output .=
        -
        -        '<script language=JavaScript><!--' . "\n"
        -
        -        . 'HideAllBut([' . join(', ', @$toExpand) . '], ' . $menuGroupNumber . ');'
        -
        -        . '// --></script>';
        -        };
        -
        -    $output .= '</div><!--Menu-->';
        -
        -    $menuNumbersAndLengthsDone = 1;
        -
        -    return $output;
        -    };
        -
        -
        -#
        -#   Function: BuildMenuSegment
        -#
        -#   A recursive function to build a segment of the menu.  *Remember to reset the <Menu Package Variables> before calling this
        -#   for the first time.*
        -#
        -#   Parameters:
        -#
        -#       outputDirectory - The output directory the menu is being built for.
        -#       menuSegment - An arrayref specifying the segment of the menu to build.  Either pass the menu itself or the contents
        -#                               of a group.
        -#       topLevel - Whether the passed segment is the top level segment or not.
        -#
        -#   Returns:
        -#
        -#       The array ( menuHTML, length ).
        -#
        -#       menuHTML - The menu segment in HTML.
        -#       groupLength - The length of the group, *not* including the contents of any subgroups, as computed from the
        -#                            <Menu Length Constants>.
        -#
        -#   Dependencies:
        -#
        -#       - <BuildMenu()> depends on the way this function formats file and index entries.
        -#
        -sub BuildMenuSegment #(outputDirectory, menuSegment, topLevel)
        -    {
        -    my ($self, $outputDirectory, $menuSegment, $topLevel) = @_;
        -
        -    my $output;
        -    my $groupLength = 0;
        -
        -    foreach my $entry (@$menuSegment)
        -        {
        -        if ($entry->Type() == ::MENU_GROUP())
        -            {
        -            my ($entryOutput, $entryLength) =
        -                $self->BuildMenuSegment($outputDirectory, $entry->GroupContent());
        -
        -            my $entryNumber;
        -
        -            if (!$menuNumbersAndLengthsDone)
        -                {
        -                $entryNumber = $menuGroupNumber;
        -                $menuGroupNumber++;
        -
        -                $menuGroupLengths{$entry} = $entryLength;
        -                $menuGroupNumbers{$entry} = $entryNumber;
        -                }
        -            else
        -                {  $entryNumber = $menuGroupNumbers{$entry};  };
        -
        -            $output .=
        -            '<div class=MEntry>'
        -                . '<div class=MGroup>'
        -
        -                    . '<a href="javascript:ToggleMenu(\'MGroupContent' . $entryNumber . '\')"'
        -                         . ($self->CommandLineOption() eq 'FramedHTML' ? ' target="_self"' : '') . '>'
        -                        . $self->StringToHTML($entry->Title())
        -                    . '</a>'
        -
        -                    . '<div class=MGroupContent id=MGroupContent' . $entryNumber . '>'
        -                        . $entryOutput
        -                    . '</div>'
        -
        -                . '</div>'
        -            . '</div>';
        -
        -            $groupLength += MENU_GROUP_LENGTH;
        -            }
        -
        -        elsif ($entry->Type() == ::MENU_FILE())
        -            {
        -            my $targetOutputFile = $self->OutputFileOf($entry->Target());
        -
        -        # Dependency: BuildMenu() depends on how this formats file entries.
        -            $output .=
        -            '<div class=MEntry>'
        -                . '<div class=MFile>'
        -                    . '<a href="' . $self->MakeRelativeURL($outputDirectory, $targetOutputFile) . '">'
        -                        . $self->StringToHTML( $entry->Title(), ADD_HIDDEN_BREAKS)
        -                    . '</a>'
        -                . '</div>'
        -            . '</div>';
        -
        -            $groupLength += MENU_FILE_LENGTH;
        -            }
        -
        -        elsif ($entry->Type() == ::MENU_TEXT())
        -            {
        -            $output .=
        -            '<div class=MEntry>'
        -                . '<div class=MText>'
        -                    . $self->StringToHTML( $entry->Title() )
        -                . '</div>'
        -            . '</div>';
        -
        -            $groupLength += MENU_TEXT_LENGTH;
        -            }
        -
        -        elsif ($entry->Type() == ::MENU_LINK())
        -            {
        -            $output .=
        -            '<div class=MEntry>'
        -                . '<div class=MLink>'
        -                    . '<a href="' . $entry->Target() . '"' . ($self->CommandLineOption() eq 'FramedHTML' ? ' target="_top"' : '') . '>'
        -                        . $self->StringToHTML( $entry->Title() )
        -                    . '</a>'
        -                . '</div>'
        -            . '</div>';
        -
        -            $groupLength += MENU_LINK_LENGTH;
        -            }
        -
        -        elsif ($entry->Type() == ::MENU_INDEX())
        -            {
        -            my $indexFile = $self->IndexFileOf($entry->Target);
        -
        -        # Dependency: BuildMenu() depends on how this formats index entries.
        -            $output .=
        -            '<div class=MEntry>'
        -                . '<div class=MIndex>'
        -                    . '<a href="' . $self->MakeRelativeURL( $outputDirectory, $self->IndexFileOf($entry->Target()) ) . '">'
        -                        . $self->StringToHTML( $entry->Title() )
        -                    . '</a>'
        -                . '</div>'
        -            . '</div>';
        -
        -            $groupLength += MENU_INDEX_LENGTH;
        -            };
        -        };
        -
        -
        -    if (!$menuNumbersAndLengthsDone)
        -        {  $menuLength += $groupLength;  };
        -
        -    return ($output, $groupLength);
        -    };
        -
        -
        -#
        -#   Function: BuildContent
        -#
        -#   Builds and returns the main page content.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The source <FileName>.
        -#       parsedFile - The parsed source file as an arrayref of <NaturalDocs::Parser::ParsedTopic> objects.
        -#
        -#   Returns:
        -#
        -#       The page content in HTML.
        -#
        -sub BuildContent #(sourceFile, parsedFile)
        -    {
        -    my ($self, $sourceFile, $parsedFile) = @_;
        -
        -    $self->ResetToolTips();
        -    $imageAnchorNumber = 1;
        -    $imageContent = undef;
        -
        -    my $output = '<div id=Content>';
        -    my $i = 0;
        -
        -    while ($i < scalar @$parsedFile)
        -        {
        -        my $anchor = $self->SymbolToHTMLSymbol($parsedFile->[$i]->Symbol());
        -
        -        my $scope = NaturalDocs::Topics->TypeInfo($parsedFile->[$i]->Type())->Scope();
        -
        -
        -        # The anchors are closed, but not around the text, so the :hover CSS style won't accidentally kick in.
        -
        -        my $headerType;
        -
        -        if ($i == 0)
        -            {  $headerType = 'h1';  }
        -        elsif ($scope == ::SCOPE_START() || $scope == ::SCOPE_END())
        -            {  $headerType = 'h2';  }
        -        else
        -            {  $headerType = 'h3';  };
        -
        -        $output .=
        -
        -        '<div class="C' . NaturalDocs::Topics->NameOfType($parsedFile->[$i]->Type(), 0, 1) . '">'
        -            . '<div class=CTopic' . ($i == 0 ? ' id=MainTopic' : '') . '>'
        -
        -                . '<' . $headerType . ' class=CTitle>'
        -                    . '<a name="' . $anchor . '"></a>'
        -                    . $self->StringToHTML( $parsedFile->[$i]->Title(), ADD_HIDDEN_BREAKS)
        -                . '</' . $headerType . '>';
        -
        -
        -        my $hierarchy;
        -        if (NaturalDocs::Topics->TypeInfo( $parsedFile->[$i]->Type() )->ClassHierarchy())
        -            {
        -            $hierarchy = $self->BuildClassHierarchy($sourceFile, $parsedFile->[$i]->Symbol());
        -            };
        -
        -        my $summary;
        -        if ($i == 0 || $scope == ::SCOPE_START() || $scope == ::SCOPE_END())
        -            {
        -            $summary .= $self->BuildSummary($sourceFile, $parsedFile, $i);
        -            };
        -
        -        my $hasBody;
        -        if (defined $hierarchy || defined $summary ||
        -            defined $parsedFile->[$i]->Prototype() || defined $parsedFile->[$i]->Body())
        -            {
        -            $output .= '<div class=CBody>';
        -            $hasBody = 1;
        -            };
        -
        -        $output .= $hierarchy;
        -
        -        if (defined $parsedFile->[$i]->Prototype())
        -            {
        -            $output .= $self->BuildPrototype($parsedFile->[$i]->Type(), $parsedFile->[$i]->Prototype(), $sourceFile);
        -            };
        -
        -        if (defined $parsedFile->[$i]->Body())
        -            {
        -            $output .= $self->NDMarkupToHTML( $sourceFile, $parsedFile->[$i]->Body(), $parsedFile->[$i]->Symbol(),
        -                                                                  $parsedFile->[$i]->Package(), $parsedFile->[$i]->Type(),
        -                                                                  $parsedFile->[$i]->Using() );
        -            };
        -
        -        $output .= $summary;
        -
        -
        -        if ($hasBody)
        -            {  $output .= '</div>';  };
        -
        -        $output .=
        -            '</div>' # CTopic
        -        . '</div>' # CType
        -        . "\n\n";
        -
        -        $i++;
        -        };
        -
        -    $output .= '</div><!--Content-->';
        -
        -    return $output;
        -    };
        -
        -
        -#
        -#   Function: BuildSummary
        -#
        -#   Builds a summary, either for the entire file or the current class/section.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The source <FileName> the summary appears in.
        -#
        -#       parsedFile - A reference to the parsed source file.
        -#
        -#       index   - The index into the parsed file to start at.  If undef or zero, it builds a summary for the entire file.  If it's the
        -#                    index of a <TopicType> that starts or ends a scope, it builds a summary for that scope
        -#
        -#   Returns:
        -#
        -#       The summary in HTML.
        -#
        -sub BuildSummary #(sourceFile, parsedFile, index)
        -    {
        -    my ($self, $sourceFile, $parsedFile, $index) = @_;
        -    my $completeSummary;
        -
        -    if (!defined $index || $index == 0)
        -        {
        -        $index = 0;
        -        $completeSummary = 1;
        -        }
        -    else
        -        {
        -        # Skip the scope entry.
        -        $index++;
        -        };
        -
        -    if ($index + 1 >= scalar @$parsedFile)
        -        {  return undef;  };
        -
        -
        -    my $scope = NaturalDocs::Topics->TypeInfo($parsedFile->[$index]->Type())->Scope();
        -
        -    # Return nothing if there's only one entry.
        -    if (!$completeSummary && ($scope == ::SCOPE_START() || $scope == ::SCOPE_END()) )
        -        {  return undef;  };
        -
        -
        -    my $indent = 0;
        -    my $inGroup;
        -
        -    my $isMarked = 0;
        -
        -    my $output =
        -    '<!--START_ND_SUMMARY-->'
        -    . '<div class=Summary><div class=STitle>Summary</div>'
        -
        -        # Not all browsers get table padding right, so we need a div to apply the border.
        -        . '<div class=SBorder>'
        -        . '<table border=0 cellspacing=0 cellpadding=0 class=STable>';
        -
        -        while ($index < scalar @$parsedFile)
        -            {
        -            my $topic = $parsedFile->[$index];
        -            my $scope = NaturalDocs::Topics->TypeInfo($topic->Type())->Scope();
        -
        -            if (!$completeSummary && ($scope == ::SCOPE_START() || $scope == ::SCOPE_END()) )
        -                {  last;  };
        -
        -
        -            # Remove modifiers as appropriate for the current entry.
        -
        -            if ($scope == ::SCOPE_START() || $scope == ::SCOPE_END())
        -                {
        -                $indent = 0;
        -                $inGroup = 0;
        -                $isMarked = 0;
        -                }
        -            elsif ($topic->Type() eq ::TOPIC_GROUP())
        -                {
        -                if ($inGroup)
        -                    {  $indent--;  };
        -
        -                $inGroup = 0;
        -                $isMarked = 0;
        -                };
        -
        -
        -            $output .=
        -             '<tr class="S' . ($index == 0 ? 'Main' : NaturalDocs::Topics->NameOfType($topic->Type(), 0, 1))
        -                . ($indent ? ' SIndent' . $indent : '') . ($isMarked ? ' SMarked' : '') .'">'
        -                . '<td class=SEntry>';
        -
        -           # Add the entry itself.
        -
        -            my $toolTipProperties;
        -
        -            # We only want a tooltip here if there's a protoype.  Otherwise it's redundant.
        -
        -            if (defined $topic->Prototype())
        -                {
        -                my $tooltipID = $self->BuildToolTip($topic->Symbol(), $sourceFile, $topic->Type(),
        -                                                                     $topic->Prototype(), $topic->Summary());
        -                $toolTipProperties = $self->BuildToolTipLinkProperties($tooltipID);
        -                };
        -
        -            $output .=
        -            '<a href="#' . $self->SymbolToHTMLSymbol($parsedFile->[$index]->Symbol()) . '" ' . $toolTipProperties . '>'
        -                . $self->StringToHTML( $parsedFile->[$index]->Title(), ADD_HIDDEN_BREAKS)
        -            . '</a>';
        -
        -
        -            $output .=
        -            '</td><td class=SDescription>';
        -
        -            if (defined $parsedFile->[$index]->Body())
        -                {
        -                $output .= $self->NDMarkupToHTML($sourceFile, $parsedFile->[$index]->Summary(),
        -                                                                     $parsedFile->[$index]->Symbol(), $parsedFile->[$index]->Package(),
        -                                                                     $parsedFile->[$index]->Type(), $parsedFile->[$index]->Using(),
        -                                                                     NDMARKUPTOHTML_SUMMARY);
        -                };
        -
        -
        -            $output .=
        -            '</td></tr>';
        -
        -
        -            # Prepare the modifiers for the next entry.
        -
        -            if ($scope == ::SCOPE_START() || $scope == ::SCOPE_END())
        -                {
        -                $indent = 1;
        -                $inGroup = 0;
        -                }
        -            elsif ($topic->Type() eq ::TOPIC_GROUP())
        -                {
        -                if (!$inGroup)
        -                    {
        -                    $indent++;
        -                    $inGroup = 1;
        -                    };
        -                };
        -
        -            $isMarked ^= 1;
        -            $index++;
        -            };
        -
        -        $output .=
        -        '</table>'
        -    . '</div>' # Body
        -    . '</div>' # Summary
        -    . "<!--END_ND_SUMMARY-->";
        -
        -    return $output;
        -    };
        -
        -
        -#
        -#   Function: BuildPrototype
        -#
        -#   Builds and returns the prototype as HTML.
        -#
        -#   Parameters:
        -#
        -#       type - The <TopicType> the prototype is from.
        -#       prototype - The prototype to format.
        -#       file - The <FileName> the prototype was defined in.
        -#
        -#   Returns:
        -#
        -#       The prototype in HTML.
        -#
        -sub BuildPrototype #(type, prototype, file)
        -    {
        -    my ($self, $type, $prototype, $file) = @_;
        -
        -    my $language = NaturalDocs::Languages->LanguageOf($file);
        -    my $prototypeObject = $language->ParsePrototype($type, $prototype);
        -
        -    my $output;
        -
        -    if ($prototypeObject->OnlyBeforeParameters())
        -        {
        -        $output =
        -        # A blockquote to scroll it if it's too long.
        -        '<blockquote>'
        -            # A surrounding table as a hack to make the div form-fit.
        -            . '<table border=0 cellspacing=0 cellpadding=0 class="Prototype"><tr>'
        -            	. '<td' . (NaturalDocs::Settings->HighlightCode() ? ' class="prettyprint"' : '') . '>'
        -	                . $self->ConvertAmpChars($prototypeObject->BeforeParameters())
        -	            . '</td>'
        -	        . '</tr></table>'
        -        . '</blockquote>';
        -        }
        -
        -    else
        -        {
        -        my $params = $prototypeObject->Parameters();
        -        my $beforeParams = $prototypeObject->BeforeParameters();
        -        my $afterParams = $prototypeObject->AfterParameters();
        -
        -	    my $highlightClass = (NaturalDocs::Settings->HighlightCode() ? ' prettyprint ' : '');
        -
        -        # Determine what features the prototype has and its length.
        -
        -        my ($hasType, $hasTypePrefix, $hasNamePrefix, $hasDefaultValue, $hasDefaultValuePrefix);
        -        my $maxParamLength = 0;
        -
        -        foreach my $param (@$params)
        -            {
        -            my $paramLength = length($param->Name());
        -
        -            if ($param->Type())
        -                {
        -                $hasType = 1;
        -                $paramLength += length($param->Type()) + 1;
        -                };
        -            if ($param->TypePrefix())
        -                {
        -                $hasTypePrefix = 1;
        -                $paramLength += length($param->TypePrefix()) + 1;
        -                };
        -            if ($param->NamePrefix())
        -                {
        -                $hasNamePrefix = 1;
        -                $paramLength += length($param->NamePrefix());
        -                };
        -            if ($param->DefaultValue())
        -                {
        -                $hasDefaultValue = 1;
        -
        -                # The length of the default value part is either the longest word, or 1/3 the total, whichever is longer.  We do this
        -                # because we don't want parameter lines wrapping to more than three lines, and there's no guarantee that the line will
        -                # wrap at all.  There's a small possibility that it could still wrap to four lines with this code, but we don't need to go
        -                # crazy(er) here.
        -
        -                my $thirdLength = length($param->DefaultValue()) / 3;
        -
        -                my @words = split(/ +/, $param->DefaultValue());
        -                my $maxWordLength = 0;
        -
        -                foreach my $word (@words)
        -                    {
        -                    if (length($word) > $maxWordLength)
        -                        {  $maxWordLength = length($word);  };
        -                    };
        -
        -                $paramLength += ($maxWordLength > $thirdLength ? $maxWordLength : $thirdLength) + 1;
        -                };
        -            if ($param->DefaultValuePrefix())
        -                {
        -                $hasDefaultValuePrefix = 1;
        -                $paramLength += length($param->DefaultValuePrefix()) + 1;
        -                };
        -
        -            if ($paramLength > $maxParamLength)
        -                {  $maxParamLength = $paramLength;  };
        -            };
        -
        -        my $useCondensed = (length($beforeParams) + $maxParamLength + length($afterParams) > 80 ? 1 : 0);
        -        my $parameterColumns = 1 + $hasType + $hasTypePrefix + $hasNamePrefix +
        -                                               $hasDefaultValue + $hasDefaultValuePrefix + $useCondensed;
        -
        -        $output =
        -        '<blockquote><table border=0 cellspacing=0 cellpadding=0 class="Prototype"><tr><td>'
        -
        -            # Stupid hack to get it to work right in IE.
        -            . '<table border=0 cellspacing=0 cellpadding=0><tr>'
        -
        -            . '<td class="PBeforeParameters ' . $highlightClass . '"' . ($useCondensed ? 'colspan=' . $parameterColumns : 'nowrap') . '>'
        -                . $self->ConvertAmpChars($beforeParams);
        -
        -                if ($beforeParams && $beforeParams !~ /[\(\[\{\<]$/)
        -                    {  $output .= '&nbsp;';  };
        -
        -            $output .=
        -            '</td>';
        -
        -            for (my $i = 0; $i < scalar @$params; $i++)
        -                {
        -                if ($useCondensed)
        -                    {
        -                    $output .= '</tr><tr><td>&nbsp;&nbsp;&nbsp;</td>';
        -                    }
        -                elsif ($i > 0)
        -                    {
        -                    # Go to the next row and and skip the BeforeParameters cell.
        -                    $output .= '</tr><tr><td></td>';
        -                    };
        -
        -                if ($language->TypeBeforeParameter())
        -                    {
        -                    if ($hasTypePrefix)
        -                        {
        -                        my $htmlTypePrefix = $self->ConvertAmpChars($params->[$i]->TypePrefix());
        -                        $htmlTypePrefix =~ s/ $/&nbsp;/;
        -
        -                        $output .=
        -                        '<td class="PTypePrefix ' . $highlightClass . '" nowrap>'
        -                            . $htmlTypePrefix
        -                        . '</td>';
        -                        };
        -
        -                    if ($hasType)
        -                        {
        -                        $output .=
        -                        '<td class="PType ' . $highlightClass . '" nowrap>'
        -                            . $self->ConvertAmpChars($params->[$i]->Type()) . '&nbsp;'
        -                        . '</td>';
        -                        };
        -
        -                    if ($hasNamePrefix)
        -                        {
        -                        $output .=
        -                        '<td class="PParameterPrefix ' . $highlightClass . '" nowrap>'
        -                            . $self->ConvertAmpChars($params->[$i]->NamePrefix())
        -                        . '</td>';
        -                        };
        -
        -                    $output .=
        -                    '<td class="PParameter ' . $highlightClass . '" nowrap' . ($useCondensed && !$hasDefaultValue ? ' width=100%' : '') . '>'
        -                        . $self->ConvertAmpChars($params->[$i]->Name())
        -                    . '</td>';
        -                    }
        -
        -                else # !$language->TypeBeforeParameter()
        -                    {
        -                    $output .=
        -                    '<td class="PParameter ' . $highlightClass . '" nowrap>'
        -                        . $self->ConvertAmpChars( $params->[$i]->NamePrefix() . $params->[$i]->Name() )
        -                    . '</td>';
        -
        -                    if ($hasType || $hasTypePrefix)
        -                        {
        -                        my $typePrefix = $params->[$i]->TypePrefix();
        -                        if ($typePrefix)
        -                            {  $typePrefix .= ' ';  };
        -
        -                        $output .=
        -                        '<td class="PType ' . $highlightClass . '" nowrap' . ($useCondensed && !$hasDefaultValue ? ' width=100%' : '') . '>'
        -                            . '&nbsp;' . $self->ConvertAmpChars( $typePrefix . $params->[$i]->Type() )
        -                        . '</td>';
        -                        };
        -                    };
        -
        -                if ($hasDefaultValuePrefix)
        -                    {
        -                    $output .=
        -                    '<td class="PDefaultValuePrefix ' . $highlightClass . '">'
        -
        -                       . '&nbsp;' . $self->ConvertAmpChars( $params->[$i]->DefaultValuePrefix() ) . '&nbsp;'
        -                    . '</td>';
        -                    };
        -
        -                if ($hasDefaultValue)
        -                    {
        -                    $output .=
        -                    '<td class="PDefaultValue ' . $highlightClass . '" width=100%>'
        -                        . ($hasDefaultValuePrefix ? '' : '&nbsp;') . $self->ConvertAmpChars( $params->[$i]->DefaultValue() )
        -                    . '</td>';
        -                    };
        -                };
        -
        -            if ($useCondensed)
        -                {  $output .= '</tr><tr>';  };
        -
        -            $output .=
        -            '<td class="PAfterParameters ' . $highlightClass . '"' . ($useCondensed ? 'colspan=' . $parameterColumns : 'nowrap') . '>'
        -                 . $self->ConvertAmpChars($afterParams);
        -
        -                if ($afterParams && $afterParams !~ /^[\)\]\}\>]/)
        -                    {  $output .= '&nbsp;';  };
        -
        -            $output .=
        -            '</td>'
        -        . '</tr></table>'
        -
        -        # Hack.
        -        . '</td></tr></table></blockquote>';
        -       };
        -
        -    return $output;
        -    };
        -
        -
        -#
        -#   Function: BuildFooter
        -#
        -#   Builds and returns the HTML footer for the page.
        -#
        -#   Parameters:
        -#
        -#       multiline - Whether it should be formatted on multiple lines or not.
        -#
        -#   Dependencies:
        -#
        -#       <Builder::HTML::UpdateFile()> and <Builder::HTML::UpdateIndex()> require this section to be surrounded with the exact
        -#       strings "<div id=Footer>" and "</div><!--Footer-->".
        -#
        -sub BuildFooter #(bool multiline)
        -    {
        -    my ($self, $multiline) = @_;
        -
        -    my $footer = NaturalDocs::Menu->Footer();
        -    my $timestamp = NaturalDocs::Menu->TimeStamp();
        -    my $divider;
        -
        -    if ($multiline)
        -        {  $divider = '</p><p>';  }
        -    else
        -        {  $divider = '&nbsp; &middot;&nbsp; ';  };
        -
        -
        -    my $output = '<div id=Footer>';
        -    if ($multiline)
        -        {  $output .= '<p>';  };
        -
        -    if (defined $footer)
        -        {
        -        $footer =~ s/\(c\)/&copy;/gi;
        -        $footer =~ s/\(tm\)/&trade;/gi;
        -        $footer =~ s/\(r\)/&reg;/gi;
        -
        -        $output .= $footer . $divider;
        -        };
        -
        -    if (defined $timestamp)
        -        {
        -        $output .= $timestamp . $divider;
        -        };
        -
        -    $output .=
        -    '<a href="' . NaturalDocs::Settings->AppURL() . '">'
        -        . 'Generated by Natural Docs'
        -    . '</a>';
        -
        -    if ($multiline)
        -        {  $output .= '</p>';  };
        -
        -    $output .=
        -    '</div><!--Footer-->';
        -
        -    return $output;
        -    };
        -
        -
        -#
        -#   Function: BuildToolTip
        -#
        -#   Builds the HTML for a symbol's tooltip and stores it in <tooltipHTML>.
        -#
        -#   Parameters:
        -#
        -#       symbol - The target <SymbolString>.
        -#       file - The <FileName> the target's defined in.
        -#       type - The symbol <TopicType>.
        -#       prototype - The target prototype, or undef for none.
        -#       summary - The target summary, or undef for none.
        -#
        -#   Returns:
        -#
        -#       If a tooltip is necessary for the link, returns the tooltip ID.  If not, returns undef.
        -#
        -sub BuildToolTip #(symbol, file, type, prototype, summary)
        -    {
        -    my ($self, $symbol, $file, $type, $prototype, $summary) = @_;
        -
        -    if (defined $prototype || defined $summary)
        -        {
        -        my $htmlSymbol = $self->SymbolToHTMLSymbol($symbol);
        -        my $number = $tooltipSymbolsToNumbers{$htmlSymbol};
        -
        -        if (!defined $number)
        -            {
        -            $number = $tooltipNumber;
        -            $tooltipNumber++;
        -
        -            $tooltipSymbolsToNumbers{$htmlSymbol} = $number;
        -
        -            $tooltipHTML .=
        -            '<div class=CToolTip id="tt' . $number . '">'
        -                . '<div class=C' . NaturalDocs::Topics->NameOfType($type, 0, 1) . '>';
        -
        -            if (defined $prototype)
        -                {
        -                $tooltipHTML .= $self->BuildPrototype($type, $prototype, $file);
        -                };
        -
        -            if (defined $summary)
        -                {
        -                # The fact that we don't have scope or using shouldn't matter because links shouldn't be included in the style anyway.
        -                $summary = $self->NDMarkupToHTML($file, $summary, undef, undef, $type, undef, NDMARKUPTOHTML_TOOLTIP);
        -                $tooltipHTML .= $summary;
        -                };
        -
        -            $tooltipHTML .=
        -                '</div>'
        -            . '</div>';
        -            };
        -
        -        return 'tt' . $number;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -#
        -#   Function: BuildToolTips
        -#
        -#   Builds and returns the tooltips for the page in HTML.
        -#
        -sub BuildToolTips
        -    {
        -    my $self = shift;
        -    return "\n<!--START_ND_TOOLTIPS-->\n" . $tooltipHTML . "<!--END_ND_TOOLTIPS-->\n\n";
        -    };
        -
        -#
        -#   Function: BuildClassHierarchy
        -#
        -#   Builds and returns a class hierarchy diagram for the passed class, if applicable.
        -#
        -#   Parameters:
        -#
        -#       file - The source <FileName>.
        -#       class - The class <SymbolString> to build the hierarchy of.
        -#
        -sub BuildClassHierarchy #(file, symbol)
        -    {
        -    my ($self, $file, $symbol) = @_;
        -
        -    my @parents = NaturalDocs::ClassHierarchy->ParentsOf($symbol);
        -    @parents = sort { ::StringCompare($a, $b) } @parents;
        -
        -    my @children = NaturalDocs::ClassHierarchy->ChildrenOf($symbol);
        -    @children = sort { ::StringCompare($a, $b) } @children;
        -
        -    if (!scalar @parents && !scalar @children)
        -        {  return undef;  };
        -
        -    my $output =
        -    '<div class=ClassHierarchy>';
        -
        -    if (scalar @parents)
        -        {
        -        $output .='<table border=0 cellspacing=0 cellpadding=0><tr><td>';
        -
        -        foreach my $parent (@parents)
        -            {
        -            $output .= $self->BuildClassHierarchyEntry($file, $parent, 'CHParent', 1);
        -            };
        -
        -        $output .= '</td></tr></table><div class=CHIndent>';
        -        };
        -
        -    $output .=
        -    '<table border=0 cellspacing=0 cellpadding=0><tr><td>'
        -        . $self->BuildClassHierarchyEntry($file, $symbol, 'CHCurrent', undef)
        -    . '</td></tr></table>';
        -
        -    if (scalar @children)
        -        {
        -        $output .=
        -        '<div class=CHIndent>'
        -            . '<table border=0 cellspacing=0 cellpadding=0><tr><td>';
        -
        -        if (scalar @children <= 5)
        -            {
        -            for (my $i = 0; $i < scalar @children; $i++)
        -                {  $output .= $self->BuildClassHierarchyEntry($file, $children[$i], 'CHChild', 1);  };
        -            }
        -        else
        -            {
        -            for (my $i = 0; $i < 4; $i++)
        -                {  $output .= $self->BuildClassHierarchyEntry($file, $children[$i], 'CHChild', 1);  };
        -
        -           $output .= '<div class=CHChildNote><div class=CHEntry>' . (scalar @children - 4) . ' other children</div></div>';
        -            };
        -
        -        $output .=
        -        '</td></tr></table>'
        -        . '</div>';
        -        };
        -
        -    if (scalar @parents)
        -        {  $output .= '</div>';  };
        -
        -    $output .=
        -    '</div>';
        -
        -    return $output;
        -    };
        -
        -
        -#
        -#   Function: BuildClassHierarchyEntry
        -#
        -#   Builds and returns a single class hierarchy entry.
        -#
        -#   Parameters:
        -#
        -#       file - The source <FileName>.
        -#       symbol - The class <SymbolString> whose entry is getting built.
        -#       style - The style to apply to the entry, such as <CHParent>.
        -#       link - Whether to build a link for this class or not.  When building the selected class' entry, this should be false.  It will
        -#               automatically handle whether the symbol is defined or not.
        -#
        -sub BuildClassHierarchyEntry #(file, symbol, style, link)
        -    {
        -    my ($self, $file, $symbol, $style, $link) = @_;
        -
        -    my @identifiers = NaturalDocs::SymbolString->IdentifiersOf($symbol);
        -    my $name = join(NaturalDocs::Languages->LanguageOf($file)->PackageSeparator(), @identifiers);
        -    $name = $self->StringToHTML($name);
        -
        -    my $output = '<div class=' . $style . '><div class=CHEntry>';
        -
        -    if ($link)
        -        {
        -        my $target = NaturalDocs::SymbolTable->Lookup($symbol, $file);
        -
        -        if (defined $target)
        -            {
        -            my $targetFile;
        -
        -            if ($target->File() ne $file)
        -                {  $targetFile = $self->MakeRelativeURL( $self->OutputFileOf($file), $self->OutputFileOf($target->File()), 1 );  };
        -            # else leave it undef
        -
        -            my $targetTooltipID = $self->BuildToolTip($symbol, $target->File(), $target->Type(),
        -                                                                          $target->Prototype(), $target->Summary());
        -
        -            my $toolTipProperties = $self->BuildToolTipLinkProperties($targetTooltipID);
        -
        -            $output .= '<a href="' . $targetFile . '#' . $self->SymbolToHTMLSymbol($symbol) . '" '
        -                            . 'class=L' . NaturalDocs::Topics->NameOfType($target->Type(), 0, 1) . ' ' . $toolTipProperties . '>'
        -                            . $name . '</a>';
        -            }
        -        else
        -            {  $output .= $name;  };
        -        }
        -    else
        -        {  $output .= $name;  };
        -
        -    $output .= '</div></div>';
        -    return $output;
        -    };
        -
        -
        -#
        -#   Function: OpeningBrowserStyles
        -#
        -#   Returns the JavaScript that will add opening browser styles if necessary.
        -#
        -sub OpeningBrowserStyles
        -    {
        -    my $self = shift;
        -
        -    return
        -
        -    '<script language=JavaScript><!--' . "\n"
        -
        -        # IE 4 and 5 don't understand 'undefined', so you can't say '!= undefined'.
        -        . 'if (browserType) {'
        -            . 'document.write("<div class=" + browserType + ">");'
        -            . 'if (browserVer) {'
        -                . 'document.write("<div class=" + browserVer + ">"); }'
        -            . '}'
        -
        -    . '// --></script>';
        -    };
        -
        -
        -#
        -#   Function: ClosingBrowserStyles
        -#
        -#   Returns the JavaScript that will close browser styles if necessary.
        -#
        -sub ClosingBrowserStyles
        -    {
        -    my $self = shift;
        -
        -    return
        -
        -    '<script language=JavaScript><!--' . "\n"
        -
        -        . 'if (browserType) {'
        -            . 'if (browserVer) {'
        -                . 'document.write("</div>"); }'
        -            . 'document.write("</div>");'
        -            . '}'
        -
        -    . '// --></script>';
        -    };
        -
        -
        -#
        -#   Function: StandardComments
        -#
        -#   Returns the standard HTML comments that should be included in every generated file.  This includes <IEWebMark()>, so this
        -#   really is required for proper functionality.
        -#
        -sub StandardComments
        -    {
        -    my $self = shift;
        -
        -    return "\n\n"
        -
        -        . '<!--  Generated by Natural Docs, version ' . NaturalDocs::Settings->TextAppVersion() . ' -->' . "\n"
        -        . '<!--  ' . NaturalDocs::Settings->AppURL() . '  -->' . "\n\n"
        -        . $self->IEWebMark() . "\n\n";
        -    };
        -
        -
        -#
        -#   Function: IEWebMark
        -#
        -#   Returns the HTML comment necessary to get around the security warnings in IE starting with Windows XP Service Pack 2.
        -#
        -#   With this mark, the HTML page is treated as if it were in the Internet security zone instead of the Local Machine zone.  This
        -#   prevents the lockdown on scripting that causes an error message to appear with each page.
        -#
        -#   More Information:
        -#
        -#       - http://www.microsoft.com/technet/prodtechnol/winxppro/maintain/sp2brows.mspx#EHAA
        -#       - http://www.phdcc.com/xpsp2.htm#markoftheweb
        -#
        -sub IEWebMark
        -    {
        -    my $self = shift;
        -
        -    return '<!-- saved from url=(0026)http://www.naturaldocs.org -->';
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Index Functions
        -
        -
        -#
        -#   Function: BuildIndexPages
        -#
        -#   Builds an index file or files.
        -#
        -#   Parameters:
        -#
        -#       type - The <TopicType> the index is limited to, or undef for none.
        -#       indexSections  - An arrayref of sections, each section being an arrayref <NaturalDocs::SymbolTable::IndexElement>
        -#                               objects.  The first section is for symbols, the second for numbers, and the rest for A through Z.
        -#       beginIndexPage - All the content of the HTML page up to where the index content should appear.
        -#       endIndexPage - All the content of the HTML page past where the index should appear.
        -#       beginSearchResultsPage - All the content of the HTML page up to where the search results content should appear.
        -#       endSearchResultsPage - All the content of the HTML page past where the search results content should appear.
        -#
        -#   Returns:
        -#
        -#       The number of pages in the index.
        -#
        -sub BuildIndexPages #(TopicType type, NaturalDocs::SymbolTable::IndexElement[] indexSections, string beginIndexPage, string endIndexPage, string beginSearchResultsPage, string endSearchResultsPage) => int
        -    {
        -    my ($self, $type, $indexSections, $beginIndexPage, $endIndexPage, $beginSearchResultsPage, $endSearchResultsPage) = @_;
        -
        -
        -    # Build the content.
        -
        -    my ($indexHTMLSections, $tooltipHTMLSections, $searchResultsHTMLSections) = $self->BuildIndexSections($indexSections);
        -
        -
        -    # Generate the search result pages.
        -
        -   for (my $i = 0; $i < 28; $i++)
        -        {
        -        if ($searchResultsHTMLSections->[$i])
        -            {
        -            my $searchResultsFileName = $self->SearchResultsFileOf($type, $searchExtensions[$i]);
        -
        -            open(INDEXFILEHANDLE, '>' . $searchResultsFileName)
        -                or die "Couldn't create output file " . $searchResultsFileName . ".\n";
        -
        -		    binmode(INDEXFILEHANDLE, ':encoding(UTF-8)');
        -
        -            print INDEXFILEHANDLE
        -
        -            $beginSearchResultsPage
        -
        -            . '<div class=SRStatus id=Loading>Loading...</div>'
        -
        -            . '<table border=0 cellspacing=0 cellpadding=0>'
        -                . $searchResultsHTMLSections->[$i]
        -            . '</table>'
        -
        -            . '<div class=SRStatus id=Searching>Searching...</div>'
        -            . '<div class=SRStatus id=NoMatches>No Matches</div>'
        -
        -            . '<script type="text/javascript"><!--' . "\n"
        -                . 'document.getElementById("Loading").style.display="none";' . "\n"
        -                . 'document.getElementById("NoMatches").style.display="none";' . "\n"
        -
        -                . 'var searchResults = new SearchResults("searchResults", "' . $self->CommandLineOption() . '");' . "\n"
        -                . 'searchResults.Search();' . "\n"
        -            . '--></script>'
        -
        -            . $endSearchResultsPage;
        -
        -            close(INDEXFILEHANDLE);
        -            };
        -        };
        -
        -    if (!$self->MadeEmptySearchResultsPage())
        -        {
        -        my $emptySearchResultsFileName = NaturalDocs::File->JoinPaths( $self->SearchResultsDirectory(), 'NoResults.html' );
        -
        -        open(INDEXFILEHANDLE, '>' . $emptySearchResultsFileName)
        -            or die "Couldn't create output file " . $emptySearchResultsFileName . ".\n";
        -
        -	    binmode(INDEXFILEHANDLE, ':encoding(UTF-8)');
        -
        -        print INDEXFILEHANDLE
        -
        -        $beginSearchResultsPage
        -        . '<div class=SRStatus id=NoMatches>No Matches</div>'
        -        . $endSearchResultsPage;
        -
        -        close(INDEXFILEHANDLE);
        -
        -        $self->SetMadeEmptySearchResultsPage(1);
        -        };
        -
        -
        -    # Generate the index pages.
        -
        -    my $page = 1;
        -    my $pageSize = 0;
        -    my @pageLocations;
        -
        -    # The maximum page size acceptable before starting a new page.  Note that this doesn't include beginPage and endPage,
        -    # because we don't want something like a large menu screwing up the calculations.
        -    use constant PAGESIZE_LIMIT => 50000;
        -
        -
        -    # File the pages.
        -
        -    for (my $i = 0; $i < scalar @$indexHTMLSections; $i++)
        -        {
        -        if (!defined $indexHTMLSections->[$i])
        -            {  next;  };
        -
        -        $pageSize += length($indexHTMLSections->[$i]) + length($tooltipHTMLSections->[$i]);
        -        $pageLocations[$i] = $page;
        -
        -        if ($pageSize + length($indexHTMLSections->[$i+1]) + length($tooltipHTMLSections->[$i+1]) > PAGESIZE_LIMIT)
        -            {
        -            $page++;
        -            $pageSize = 0;
        -            };
        -        };
        -
        -
        -    # Build the pages.
        -
        -    my $indexFileName;
        -    $page = -1;
        -    my $oldPage = -1;
        -    my $tooltips;
        -    my $firstHeading;
        -
        -    for (my $i = 0; $i < scalar @$indexHTMLSections; $i++)
        -        {
        -        if (!defined $indexHTMLSections->[$i])
        -            {  next;  };
        -
        -        $page = $pageLocations[$i];
        -
        -        # Switch files if we need to.
        -
        -        if ($page != $oldPage)
        -            {
        -            if ($oldPage != -1)
        -                {
        -                print INDEXFILEHANDLE '</table>' . $tooltips . $endIndexPage;
        -                close(INDEXFILEHANDLE);
        -                $tooltips = undef;
        -                };
        -
        -            $indexFileName = $self->IndexFileOf($type, $page);
        -
        -            open(INDEXFILEHANDLE, '>' . $indexFileName)
        -                or die "Couldn't create output file " . $indexFileName . ".\n";
        -
        -		    binmode(INDEXFILEHANDLE, ':encoding(UTF-8)');
        -
        -            print INDEXFILEHANDLE $beginIndexPage . $self->BuildIndexNavigationBar($type, $page, \@pageLocations)
        -                                              . '<table border=0 cellspacing=0 cellpadding=0>';
        -
        -            $oldPage = $page;
        -            $firstHeading = 1;
        -            };
        -
        -        print INDEXFILEHANDLE
        -        '<tr>'
        -            . '<td class=IHeading' . ($firstHeading ? ' id=IFirstHeading' : '') . '>'
        -                . '<a name="' . $indexAnchors[$i] . '"></a>'
        -                 . $indexHeadings[$i]
        -            . '</td>'
        -            . '<td></td>'
        -        . '</tr>'
        -
        -        . $indexHTMLSections->[$i];
        -
        -        $firstHeading = 0;
        -        $tooltips .= $tooltipHTMLSections->[$i];
        -        };
        -
        -    if ($page != -1)
        -        {
        -        print INDEXFILEHANDLE '</table>' . $tooltips . $endIndexPage;
        -        close(INDEXFILEHANDLE);
        -        }
        -
        -    # Build a dummy page so there's something at least.
        -    else
        -        {
        -        $indexFileName = $self->IndexFileOf($type, 1);
        -
        -        open(INDEXFILEHANDLE, '>' . $indexFileName)
        -            or die "Couldn't create output file " . $indexFileName . ".\n";
        -
        -    	binmode(INDEXFILEHANDLE, ':encoding(UTF-8)');
        -
        -        print INDEXFILEHANDLE
        -            $beginIndexPage
        -            . $self->BuildIndexNavigationBar($type, 1, \@pageLocations)
        -            . 'There are no entries in the ' . lc( NaturalDocs::Topics->NameOfType($type) ) . ' index.'
        -            . $endIndexPage;
        -
        -        close(INDEXFILEHANDLE);
        -        };
        -
        -
        -    return $page;
        -    };
        -
        -
        -#
        -#   Function: BuildIndexSections
        -#
        -#   Builds and returns the index and search results sections in HTML.
        -#
        -#   Parameters:
        -#
        -#       index  - An arrayref of sections, each section being an arrayref <NaturalDocs::SymbolTable::IndexElement> objects.
        -#                   The first section is for symbols, the second for numbers, and the rest for A through Z.
        -#
        -#   Returns:
        -#
        -#       The arrayref ( indexSections, tooltipSections, searchResultsSections ).
        -#
        -#       Index 0 is the symbols, index 1 is the numbers, and each following index is A through Z.  The content of each section
        -#       is its HTML, or undef if there is nothing for that section.
        -#
        -sub BuildIndexSections #(NaturalDocs::SymbolTable::IndexElement[] index) => ( string[], string[], string[] )
        -    {
        -    my ($self, $indexSections) = @_;
        -
        -    $self->ResetToolTips();
        -    %searchResultIDs = ( );
        -
        -    my $contentSections = [ ];
        -    my $tooltipSections = [ ];
        -    my $searchResultsSections = [ ];
        -
        -    for (my $section = 0; $section < scalar @$indexSections; $section++)
        -        {
        -        if (defined $indexSections->[$section])
        -            {
        -            my $total = scalar @{$indexSections->[$section]};
        -
        -            for (my $i = 0; $i < $total; $i++)
        -                {
        -                my $id;
        -
        -                if ($i == 0)
        -                    {
        -                    if ($total == 1)
        -                        {  $id = 'IOnlySymbolPrefix';  }
        -                    else
        -                        {  $id = 'IFirstSymbolPrefix';  };
        -                    }
        -                elsif ($i == $total - 1)
        -                    {  $id = 'ILastSymbolPrefix';  };
        -
        -                my ($content, $searchResult) = $self->BuildIndexElement($indexSections->[$section]->[$i], $id);
        -                $contentSections->[$section] .= $content;
        -                $searchResultsSections->[$section] .= $searchResult;
        -                };
        -
        -            $tooltipSections->[$section] .= $self->BuildToolTips();
        -            $self->ResetToolTips(1);
        -            };
        -        };
        -
        -
        -    return ( $contentSections, $tooltipSections, $searchResultsSections );
        -    };
        -
        -
        -#
        -#   Function: BuildIndexElement
        -#
        -#   Converts a <NaturalDocs::SymbolTable::IndexElement> to HTML and returns it.  It will handle all sub-elements automatically.
        -#
        -#   Parameters:
        -#
        -#       element - The <NaturalDocs::SymbolTable::IndexElement> to build.
        -#       cssID - The CSS ID to apply to the prefix.
        -#
        -#   Recursion-Only Parameters:
        -#
        -#       These parameters are used internally for recursion, and should not be set.
        -#
        -#       symbol - If the element is below symbol level, the <SymbolString> to use.
        -#       package - If the element is below package level, the package <SymbolString> to use.
        -#       hasPackage - Whether the element is below package level.  Is necessary because package may need to be undef.
        -#
        -#   Returns:
        -#
        -#       The array ( indexHTML, searchResultHTML ) which is the element in the respective HTML forms.
        -#
        -sub BuildIndexElement #(NaturalDocs::SymbolTable::IndexElement element, string cssID, SymbolString symbol, SymbolString package, bool hasPackage) => ( string, string )
        -    {
        -    my ($self, $element, $cssID, $symbol, $package, $hasPackage) = @_;
        -
        -
        -    # If we're doing a file sub-index entry...
        -
        -    if ($hasPackage)
        -        {
        -        my ($inputDirectory, $relativePath) = NaturalDocs::Settings->SplitFromInputDirectory($element->File());
        -
        -        return $self->BuildIndexLink($self->StringToHTML($relativePath, ADD_HIDDEN_BREAKS), $symbol,
        -                                                                                 $package, $element->File(), $element->Type(),
        -                                                                                 $element->Prototype(), $element->Summary(), 'IFile');
        -        }
        -
        -
        -    # If we're doing a package sub-index entry...
        -
        -    elsif (defined $symbol)
        -
        -        {
        -        my $text;
        -
        -        if ($element->Package())
        -            {
        -            $text = NaturalDocs::SymbolString->ToText($element->Package(), $element->PackageSeparator());
        -            $text = $self->StringToHTML($text, ADD_HIDDEN_BREAKS);
        -            }
        -        else
        -            {  $text = 'Global';  };
        -
        -        if (!$element->HasMultipleFiles())
        -            {
        -            return $self->BuildIndexLink($text, $symbol, $element->Package(), $element->File(), $element->Type(),
        -                                                      $element->Prototype(), $element->Summary(), 'IParent');
        -            }
        -
        -        else
        -            {
        -            my $indexHTML =
        -            '<span class=IParent>'
        -                . $text
        -            . '</span>'
        -            . '<div class=ISubIndex>';
        -
        -            my $searchResultHTML = $indexHTML;
        -
        -            my $fileElements = $element->File();
        -            foreach my $fileElement (@$fileElements)
        -                {
        -                my ($i, $s) = $self->BuildIndexElement($fileElement, $cssID, $symbol, $element->Package(), 1);
        -                $indexHTML .= $i;
        -                $searchResultHTML .= $s;
        -                };
        -
        -            $indexHTML .= '</div>';
        -            $searchResultHTML .= '</div>';
        -
        -            return ($indexHTML, $searchResultHTML);
        -            };
        -        }
        -
        -
        -    # If we're doing a top-level symbol entry...
        -
        -    else
        -        {
        -        my $symbolText = $self->StringToHTML($element->SortableSymbol(), ADD_HIDDEN_BREAKS);
        -        my $symbolPrefix = $self->StringToHTML($element->IgnoredPrefix());
        -        my $searchResultID = $self->StringToSearchResultID($element->SortableSymbol());
        -
        -        my $indexHTML =
        -        '<tr>'
        -            . '<td class=ISymbolPrefix' . ($cssID ? ' id=' . $cssID : '') . '>'
        -                . ($symbolPrefix || '&nbsp;')
        -            . '</td><td class=IEntry>';
        -
        -        my $searchResultsHTML =
        -        '<div class=SRResult id=' . $searchResultID . '><div class=IEntry>';
        -
        -            if ($symbolPrefix)
        -                {  $searchResultsHTML .= '<span class=ISymbolPrefix>' . $symbolPrefix . '</span>';  };
        -
        -        if (!$element->HasMultiplePackages())
        -            {
        -            my $packageText;
        -
        -            if (defined $element->Package())
        -                {
        -                $packageText = NaturalDocs::SymbolString->ToText($element->Package(), $element->PackageSeparator());
        -                $packageText = $self->StringToHTML($packageText, ADD_HIDDEN_BREAKS);
        -                };
        -
        -            if (!$element->HasMultipleFiles())
        -                {
        -                my ($i, $s) =
        -                    $self->BuildIndexLink($symbolText, $element->Symbol(), $element->Package(), $element->File(),
        -                                                     $element->Type(), $element->Prototype(), $element->Summary(), 'ISymbol');
        -                $indexHTML .= $i;
        -                $searchResultsHTML .= $s;
        -
        -                if (defined $packageText)
        -                    {
        -                    $indexHTML .=
        -                    ', <span class=IParent>'
        -                        . $packageText
        -                    . '</span>';
        -
        -                    $searchResultsHTML .=
        -                    ', <span class=IParent>'
        -                        . $packageText
        -                    . '</span>';
        -                    };
        -                }
        -            else # hasMultipleFiles but not multiplePackages
        -                {
        -                $indexHTML .=
        -                '<span class=ISymbol>'
        -                    . $symbolText
        -                . '</span>';
        -
        -                $searchResultsHTML .=
        -                q{<a href="javascript:searchResults.Toggle('} . $searchResultID . q{')" class=ISymbol>}
        -                    . $symbolText
        -                . '</a>';
        -
        -                my $output;
        -
        -                if (defined $packageText)
        -                    {
        -                    $output .=
        -                    ', <span class=IParent>'
        -                        . $packageText
        -                    . '</span>';
        -                    };
        -
        -                $output .=
        -                '<div class=ISubIndex>';
        -
        -                $indexHTML .= $output;
        -                $searchResultsHTML .= $output;
        -
        -                my $fileElements = $element->File();
        -                foreach my $fileElement (@$fileElements)
        -                    {
        -                    my ($i, $s) = $self->BuildIndexElement($fileElement, $cssID, $element->Symbol(), $element->Package(), 1);
        -                    $indexHTML .= $i;
        -                    $searchResultsHTML .= $s;
        -                    };
        -
        -                $indexHTML .= '</div>';
        -                $searchResultsHTML .= '</div>';
        -                };
        -            }
        -
        -        else # hasMultiplePackages
        -            {
        -            $indexHTML .=
        -            '<span class=ISymbol>'
        -                . $symbolText
        -            . '</span>'
        -            . '<div class=ISubIndex>';
        -
        -            $searchResultsHTML .=
        -            q{<a href="javascript:searchResults.Toggle('} . $searchResultID . q{')" class=ISymbol>}
        -                . $symbolText
        -            . '</a>'
        -            . '<div class=ISubIndex>';
        -
        -            my $packageElements = $element->Package();
        -            foreach my $packageElement (@$packageElements)
        -                {
        -                my ($i, $s) = $self->BuildIndexElement($packageElement, $cssID, $element->Symbol());
        -                $indexHTML .= $i;
        -                $searchResultsHTML .= $s;
        -                };
        -
        -            $indexHTML .= '</div>';
        -            $searchResultsHTML .= '</div>';
        -            };
        -
        -        $indexHTML .= '</td></tr>';
        -        $searchResultsHTML .= '</div></div>';
        -
        -        return ($indexHTML, $searchResultsHTML);
        -        };
        -    };
        -
        -
        -#
        -#   Function: BuildIndexLink
        -#
        -#   Builds and returns the HTML associated with an index link.  The HTML will be the a href tag, the text, and the closing tag.
        -#
        -#   Parameters:
        -#
        -#       text - The text of the link *in HTML*.  Use <IndexSymbolToHTML()> if necessary.
        -#       symbol - The partial <SymbolString> to link to.
        -#       package - The package <SymbolString> of the symbol.
        -#       file - The <FileName> the symbol is defined in.
        -#       type - The <TopicType> of the symbol.
        -#       prototype - The prototype of the symbol, or undef if none.
        -#       summary - The summary of the symbol, or undef if none.
        -#       style - The CSS style to apply to the link.
        -#
        -#   Returns:
        -#
        -#       The array ( indexHTML, searchResultHTML ) which is the link in the respective forms.
        -#
        -sub BuildIndexLink #(string text, SymbolString symbol, SymbolString package, FileName file, TopicType type, string prototype, string summary, string style) => ( string, string )
        -    {
        -    my ($self, $text, $symbol, $package, $file, $type, $prototype, $summary, $style) = @_;
        -
        -    $symbol = NaturalDocs::SymbolString->Join($package, $symbol);
        -
        -    my $targetTooltipID = $self->BuildToolTip($symbol, $file, $type, $prototype, $summary);
        -    my $toolTipProperties = $self->BuildToolTipLinkProperties($targetTooltipID);
        -
        -    my $indexHTML = '<a href="' . $self->MakeRelativeURL( $self->IndexDirectory(), $self->OutputFileOf($file) )
        -                                         . '#' . $self->SymbolToHTMLSymbol($symbol) . '" ' . $toolTipProperties . ' '
        -                                . 'class=' . $style . '>' . $text . '</a>';
        -    my $searchResultHTML = '<a href="' . $self->MakeRelativeURL( $self->SearchResultsDirectory(), $self->OutputFileOf($file) )
        -                                         . '#' . $self->SymbolToHTMLSymbol($symbol) . '" '
        -                                         . ($self->CommandLineOption eq 'HTML' ? 'target=_parent ' : '')
        -                                . 'class=' . $style . '>' . $text . '</a>';
        -
        -    return ($indexHTML, $searchResultHTML);
        -    };
        -
        -
        -#
        -#   Function: BuildIndexNavigationBar
        -#
        -#   Builds a navigation bar for a page of the index.
        -#
        -#   Parameters:
        -#
        -#       type - The <TopicType> of the index, or undef for general.
        -#       page - The page of the index the navigation bar is for.
        -#       locations - An arrayref of the locations of each section.  Index 0 is for the symbols, index 1 for the numbers, and the rest
        -#                       for each letter.  The values are the page numbers where the sections are located.
        -#
        -sub BuildIndexNavigationBar #(type, page, locations)
        -    {
        -    my ($self, $type, $page, $locations) = @_;
        -
        -    my $output = '<div class=INavigationBar>';
        -
        -    for (my $i = 0; $i < scalar @indexHeadings; $i++)
        -        {
        -        if ($i != 0)
        -            {  $output .= ' &middot; ';  };
        -
        -        if (defined $locations->[$i])
        -            {
        -            $output .= '<a href="';
        -
        -            if ($locations->[$i] != $page)
        -                {  $output .= $self->RelativeIndexFileOf($type, $locations->[$i]);  };
        -
        -            $output .= '#' . $indexAnchors[$i] . '">' . $indexHeadings[$i] . '</a>';
        -            }
        -        else
        -            {
        -            $output .= $indexHeadings[$i];
        -            };
        -        };
        -
        -    $output .= '</div>';
        -
        -    return $output;
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: File Functions
        -
        -
        -#
        -#   Function: PurgeIndexFiles
        -#
        -#   Removes all or some of the output files for an index.
        -#
        -#   Parameters:
        -#
        -#       type  - The index <TopicType>.
        -#       indexSections  - An arrayref of sections, each section being an arrayref <NaturalDocs::SymbolTable::IndexElement>
        -#                               objects.  The first section is for symbols, the second for numbers, and the rest for A through Z.  May be
        -#                               undef.
        -#       startingPage - If defined, only pages starting with this number will be removed.  Otherwise all pages will be removed.
        -#
        -sub PurgeIndexFiles #(TopicType type, optional NaturalDocs::SymbolTable::IndexElement[] indexSections, optional int startingPage)
        -    {
        -    my ($self, $type, $indexSections, $page) = @_;
        -
        -    # First the regular index pages.
        -
        -    if (!defined $page)
        -        {  $page = 1;  };
        -
        -    for (;;)
        -        {
        -        my $file = $self->IndexFileOf($type, $page);
        -
        -        if (-e $file)
        -            {
        -            unlink($file);
        -            $page++;
        -            }
        -        else
        -            {
        -            last;
        -            };
        -        };
        -
        -
        -    # Next the search results.
        -
        -    for (my $i = 0; $i < 28; $i++)
        -        {
        -        if (!$indexSections || !$indexSections->[$i])
        -            {
        -            my $file = $self->SearchResultsFileOf($type, $searchExtensions[$i]);
        -
        -            if (-e $file)
        -                {  unlink($file);  };
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: OutputFileOf
        -#
        -#   Returns the output file name of the source file.  Will be undef if it is not a file from a valid input directory.
        -#
        -sub OutputFileOf #(sourceFile)
        -    {
        -    my ($self, $sourceFile) = @_;
        -
        -    my ($inputDirectory, $relativeSourceFile) = NaturalDocs::Settings->SplitFromInputDirectory($sourceFile);
        -    if (!defined $inputDirectory)
        -        {  return undef;  };
        -
        -    my $outputDirectory = NaturalDocs::Settings->OutputDirectoryOf($self);
        -    my $inputDirectoryName = NaturalDocs::Settings->InputDirectoryNameOf($inputDirectory);
        -
        -    $outputDirectory = NaturalDocs::File->JoinPaths( $outputDirectory,
        -                                                                            'files' . ($inputDirectoryName != 1 ? $inputDirectoryName : ''), 1 );
        -
        -    # We need to change any extensions to dashes because Apache will think file.pl.html is a script.
        -    # We also need to add a dash if the file doesn't have an extension so there'd be no conflicts with index.html,
        -    # FunctionIndex.html, etc.
        -
        -    if (!($relativeSourceFile =~ tr/./-/))
        -        {  $relativeSourceFile .= '-';  };
        -
        -    $relativeSourceFile =~ tr/ &?(){};#/_/;
        -    $relativeSourceFile .= '.html';
        -
        -    return NaturalDocs::File->JoinPaths($outputDirectory, $relativeSourceFile);
        -    };
        -
        -
        -#
        -#   Function: OutputImageOf
        -#
        -#   Returns the output image file name of the source image file.  Will be undef if it is not a file from a valid input directory.
        -#
        -sub OutputImageOf #(sourceImageFile)
        -    {
        -    my ($self, $sourceImageFile) = @_;
        -
        -    my $outputDirectory = NaturalDocs::Settings->OutputDirectoryOf($self);
        -    my $topLevelDirectory;
        -
        -    my ($inputDirectory, $relativeImageFile) = NaturalDocs::Settings->SplitFromInputDirectory($sourceImageFile);
        -
        -    if (defined $inputDirectory)
        -        {
        -        my $inputDirectoryName = NaturalDocs::Settings->InputDirectoryNameOf($inputDirectory);
        -        $topLevelDirectory = 'files' . ($inputDirectoryName != 1 ? $inputDirectoryName : '');
        -        }
        -    else
        -        {
        -        ($inputDirectory, $relativeImageFile) = NaturalDocs::Settings->SplitFromImageDirectory($sourceImageFile);
        -
        -        if (!defined $inputDirectory)
        -            {  return undef;  };
        -
        -        my $inputDirectoryName = NaturalDocs::Settings->ImageDirectoryNameOf($inputDirectory);
        -        $topLevelDirectory = 'images' . ($inputDirectoryName != 1 ? $inputDirectoryName : '');
        -        }
        -
        -
        -    $outputDirectory = NaturalDocs::File->JoinPaths($outputDirectory, $topLevelDirectory, 1);
        -
        -    $relativeImageFile =~ tr/ /_/;
        -
        -    return NaturalDocs::File->JoinPaths($outputDirectory, $relativeImageFile);
        -    };
        -
        -
        -#
        -#   Function: IndexDirectory
        -#
        -#   Returns the directory of the index files.
        -#
        -sub IndexDirectory
        -    {
        -    my $self = shift;
        -    return NaturalDocs::File->JoinPaths( NaturalDocs::Settings->OutputDirectoryOf($self), 'index', 1);
        -    };
        -
        -
        -#
        -#   Function: IndexFileOf
        -#
        -#   Returns the output file name of the index file.
        -#
        -#   Parameters:
        -#
        -#       type  - The <TopicType> of the index.
        -#       page  - The page number.  Undef is the same as one.
        -#
        -sub IndexFileOf #(type, page)
        -    {
        -    my ($self, $type, $page) = @_;
        -    return NaturalDocs::File->JoinPaths( $self->IndexDirectory(), $self->RelativeIndexFileOf($type, $page) );
        -    };
        -
        -
        -#
        -#   Function: RelativeIndexFileOf
        -#
        -#   Returns the output file name of the index file, relative to other index files.
        -#
        -#   Parameters:
        -#
        -#       type  - The <TopicType> of the index.
        -#       page  - The page number.  Undef is the same as one.
        -#
        -sub RelativeIndexFileOf #(type, page)
        -    {
        -    my ($self, $type, $page) = @_;
        -    return NaturalDocs::Topics->NameOfType($type, 1, 1) . (defined $page && $page != 1 ? $page : '') . '.html';
        -    };
        -
        -
        -#
        -#   Function: SearchResultsDirectory
        -#
        -#   Returns the directory of the search results files.
        -#
        -sub SearchResultsDirectory
        -    {
        -    my $self = shift;
        -    return NaturalDocs::File->JoinPaths( NaturalDocs::Settings->OutputDirectoryOf($self), 'search', 1);
        -    };
        -
        -
        -#
        -#   Function: SearchResultsFileOf
        -#
        -#   Returns the output file name of the search result file.
        -#
        -#   Parameters:
        -#
        -#       type  - The <TopicType> of the index.
        -#       extra - The string to add to the end of the file name, such as "A" or "Symbols".
        -#
        -sub SearchResultsFileOf #(TopicType type, string extra)
        -    {
        -    my ($self, $type, $extra) = @_;
        -
        -    my $fileName = NaturalDocs::Topics->NameOfType($type, 1, 1) . $extra . '.html';
        -
        -    return NaturalDocs::File->JoinPaths( $self->SearchResultsDirectory(), $fileName );
        -    };
        -
        -
        -#
        -#   Function: CSSDirectory
        -#
        -#   Returns the directory of the CSS files.
        -#
        -sub CSSDirectory
        -    {
        -    my $self = shift;
        -    return NaturalDocs::File->JoinPaths( NaturalDocs::Settings->OutputDirectoryOf($self), 'styles', 1);
        -    };
        -
        -
        -#
        -#   Function: MainCSSFile
        -#
        -#   Returns the location of the main CSS file.
        -#
        -sub MainCSSFile
        -    {
        -    my $self = shift;
        -    return NaturalDocs::File->JoinPaths( $self->CSSDirectory(), 'main.css' );
        -    };
        -
        -
        -#
        -#   Function: JavaScriptDirectory
        -#
        -#   Returns the directory of the JavaScript files.
        -#
        -sub JavaScriptDirectory
        -    {
        -    my $self = shift;
        -    return NaturalDocs::File->JoinPaths( NaturalDocs::Settings->OutputDirectoryOf($self), 'javascript', 1);
        -    };
        -
        -
        -#
        -#   Function: MainJavaScriptFile
        -#
        -#   Returns the location of the main JavaScript file.
        -#
        -sub MainJavaScriptFile
        -    {
        -    my $self = shift;
        -    return NaturalDocs::File->JoinPaths( $self->JavaScriptDirectory(), 'main.js' );
        -    };
        -
        -
        -#
        -#   Function: PrettifyJavaScriptFile
        -#
        -#   Returns the location of the Google Prettify JavaScript file.
        -#
        -sub PrettifyJavaScriptFile
        -    {
        -    my $self = shift;
        -    return NaturalDocs::File->JoinPaths( $self->JavaScriptDirectory(), 'prettify.js' );
        -    };
        -
        -
        -#
        -#   Function: SearchDataJavaScriptFile
        -#
        -#   Returns the location of the search data JavaScript file.
        -#
        -sub SearchDataJavaScriptFile
        -    {
        -    my $self = shift;
        -    return NaturalDocs::File->JoinPaths( $self->JavaScriptDirectory(), 'searchdata.js' );
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -
        -#
        -#   Function: IndexTitleOf
        -#
        -#   Returns the page title of the index file.
        -#
        -#   Parameters:
        -#
        -#       type  - The type of index.
        -#
        -sub IndexTitleOf #(type)
        -    {
        -    my ($self, $type) = @_;
        -
        -    return ($type eq ::TOPIC_GENERAL() ? '' : NaturalDocs::Topics->NameOfType($type) . ' ') . 'Index';
        -    };
        -
        -#
        -#   Function: MakeRelativeURL
        -#
        -#   Returns a relative path between two files in the output tree and returns it in URL format.
        -#
        -#   Parameters:
        -#
        -#       baseFile    - The base <FileName> in local format, *not* in URL format.
        -#       targetFile  - The target <FileName> of the link in local format, *not* in URL format.
        -#       baseHasFileName - Whether baseFile has a file name attached or is just a path.
        -#
        -#   Returns:
        -#
        -#       The relative URL to the target.
        -#
        -sub MakeRelativeURL #(FileName baseFile, FileName targetFile, bool baseHasFileName) -> string relativeURL
        -    {
        -    my ($self, $baseFile, $targetFile, $baseHasFileName) = @_;
        -
        -    if ($baseHasFileName)
        -        {  $baseFile = NaturalDocs::File->NoFileName($baseFile)  };
        -
        -    my $relativePath = NaturalDocs::File->MakeRelativePath($baseFile, $targetFile);
        -
        -    return $self->ConvertAmpChars( NaturalDocs::File->ConvertToURL($relativePath) );
        -    };
        -
        -#
        -#   Function: StringToHTML
        -#
        -#   Converts a text string to HTML.  Does not apply paragraph tags or accept formatting tags.
        -#
        -#   Parameters:
        -#
        -#       string - The string to convert.
        -#       addHiddenBreaks - Whether to add hidden breaks to the string.  You can use <ADD_HIDDEN_BREAKS> for this parameter
        -#                                   if you want to make the calling code clearer.
        -#
        -#   Returns:
        -#
        -#       The string in HTML.
        -#
        -sub StringToHTML #(string, addHiddenBreaks)
        -    {
        -    my ($self, $string, $addHiddenBreaks) = @_;
        -
        -    $string =~ s/&/&amp;/g;
        -    $string =~ s/</&lt;/g;
        -    $string =~ s/>/&gt;/g;
        -
        -    # Me likey the fancy quotes.  They work in IE 4+, Mozilla, and Opera 5+.  We've already abandoned NS4 with the CSS
        -    # styles, so might as well.
        -    $string =~ s/^\'/&lsquo;/gm;
        -    $string =~ s/([\ \(\[\{])\'/$1&lsquo;/g;
        -    $string =~ s/\'/&rsquo;/g;
        -
        -    $string =~ s/^\"/&ldquo;/gm;
        -    $string =~ s/([\ \(\[\{])\"/$1&ldquo;/g;
        -    $string =~ s/\"/&rdquo;/g;
        -
        -    # Me likey the double spaces too.  As you can probably tell, I like print-formatting better than web-formatting.  The indented
        -    # paragraphs without blank lines in between them do become readable when you have fancy quotes and double spaces too.
        -    $string = $self->AddDoubleSpaces($string);
        -
        -    if ($addHiddenBreaks)
        -        {  $string = $self->AddHiddenBreaks($string);  };
        -
        -    return $string;
        -    };
        -
        -
        -#
        -#   Function: SymbolToHTMLSymbol
        -#
        -#   Converts a <SymbolString> to a HTML symbol, meaning one that is safe to include in anchor and link tags.  You don't need
        -#   to pass the result to <ConvertAmpChars()>.
        -#
        -sub SymbolToHTMLSymbol #(symbol)
        -    {
        -    my ($self, $symbol) = @_;
        -
        -    my @identifiers = NaturalDocs::SymbolString->IdentifiersOf($symbol);
        -    my $htmlSymbol = join('.', @identifiers);
        -
        -    # If only Mozilla was nice about putting special characters in URLs like IE and Opera are, I could leave spaces in and replace
        -    # "<>& with their amp chars.  But alas, Mozilla shows them as %20, etc. instead.  It would have made for nice looking URLs.
        -    $htmlSymbol =~ tr/ \"<>\?&%/_/d;
        -
        -    return $htmlSymbol;
        -    };
        -
        -
        -#
        -#   Function: StringToSearchResultID
        -#
        -#   Takes a text string and translates it into something that can be used as a CSS ID.
        -#
        -#   Parameters:
        -#
        -#       string - The string to convert
        -#       dontIncrement - If set, it reuses the last generated ID.  Otherwise it generates a new one if it matches a previously
        -#                               generated one in a case-insensitive way.
        -#
        -sub StringToSearchResultID #(string string, bool dontIncrement = 0) => string
        -    {
        -    my ($self, $string, $dontIncrement) = @_;
        -
        -    $string =~ s/\_/_und/g;
        -    $string =~ s/ +/_spc/g;
        -
        -    my %translation = ( '~' => '_til', '!' => '_exc', '@' => '_att', '#' => '_num', '$' => '_dol', '%' => '_pct', '^' => '_car',
        -                                  '&' => '_amp', '*' => '_ast', '(' => '_lpa', ')' => '_rpa', '-' => '_min', '+' => '_plu', '=' => '_equ',
        -                                  '{' => '_lbc', '}' => '_rbc', '[' => '_lbk', ']' => '_rbk', ':' => '_col', ';' => '_sco', '"' => '_quo',
        -                                  '\'' => '_apo', '<' => '_lan', '>' => '_ran', ',' => '_com', '.' => '_per', '?' => '_que', '/' => '_sla' );
        -
        -    $string =~ s/([\~\!\@\#\$\%\^\&\*\(\)\-\+\=\{\}\[\]\:\;\"\'\<\>\,\.\?\/])/$translation{$1}/ge;
        -    $string =~ s/[^a-z0-9_]/_zzz/gi;
        -
        -    my $number = $searchResultIDs{lc($string)};
        -
        -    if (!$number)
        -        {  $number = 1;  }
        -    elsif (!$dontIncrement)
        -        {  $number++;  };
        -
        -    $searchResultIDs{lc($string)} = $number;
        -
        -    return 'SR' . ($number == 1 ? '' : $number) . '_' . $string;
        -    };
        -
        -
        -#
        -#   Function: NDMarkupToHTML
        -#
        -#   Converts a block of <NDMarkup> to HTML.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The source <FileName> the <NDMarkup> appears in.
        -#       text    - The <NDMarkup> text to convert.
        -#       symbol - The topic <SymbolString> the <NDMarkup> appears in.
        -#       package  - The package <SymbolString> the <NDMarkup> appears in.
        -#       type - The <TopicType> the <NDMarkup> appears in.
        -#       using - An arrayref of scope <SymbolStrings> the <NDMarkup> also has access to, or undef if none.
        -#       style - Set to one of the <NDMarkupToHTML Styles> or leave undef for general.
        -#
        -#   Returns:
        -#
        -#       The text in HTML.
        -#
        -sub NDMarkupToHTML #(sourceFile, text, symbol, package, type, using, style)
        -    {
        -    my ($self, $sourceFile, $text, $symbol, $package, $type, $using, $style) = @_;
        -
        -    my $dlSymbolBehavior;
        -
        -    if ($type eq ::TOPIC_ENUMERATION())
        -        {  $dlSymbolBehavior = NaturalDocs::Languages->LanguageOf($sourceFile)->EnumValues();  }
        -   elsif (NaturalDocs::Topics->TypeInfo($type)->Scope() == ::SCOPE_ALWAYS_GLOBAL())
        -        {  $dlSymbolBehavior = ::ENUM_GLOBAL();  }
        -    else
        -        {  $dlSymbolBehavior = ::ENUM_UNDER_PARENT();  };
        -
        -    my $output;
        -    my $inCode;
        -
        -    my @splitText = split(/(<\/?code(?: type="[^"]+")?>)/, $text);
        -
        -    while (scalar @splitText)
        -        {
        -        $text = shift @splitText;
        -
        -        if ($text =~ /<code type="([^"]+)">/)
        -            {
        -            my $codeType = $1;
        -
        -            my $highlight = ( ($codeType eq "code" && NaturalDocs::Settings->HighlightCode()) ||
        -            						  ($codeType eq "anonymous" && NaturalDocs::Settings->HighlightAnonymous()) );
        -
        -            $output .= '<blockquote><pre' . ($highlight ? ' class="prettyprint"' : '') . '>';
        -            $inCode = 1;
        -            }
        -        elsif ($text eq '</code>')
        -            {
        -            $output .= '</pre></blockquote>';
        -            $inCode = undef;
        -            }
        -        elsif ($inCode)
        -            {
        -            # Leave line breaks in.
        -            $output .= $text;
        -            }
        -        else
        -            {
        -            # Format non-code text.
        -
        -            # Convert linked images.
        -            if ($text =~ /<img mode=\"link\"/)
        -                {
        -                if ($style == NDMARKUPTOHTML_GENERAL)
        -                    {
        -                    # Split by tags we would want to see the linked images appear after.  For example, an image link appearing in
        -                    # the middle of a paragraph would appear after the end of that paragraph.
        -                    my @imageBlocks = split(/(<p>.*?<\/p>|<dl>.*?<\/dl>|<ul>.*?<\/ul>)/, $text);
        -                    $text = undef;
        -
        -                    foreach my $imageBlock (@imageBlocks)
        -                        {
        -                        $imageBlock =~ s{<img mode=\"link\" target=\"([^\"]*)\" original=\"([^\"]*)\">}
        -                                                {$self->BuildImage($sourceFile, 'link', $1, $2)}ge;
        -
        -                        $text .= $imageBlock . $imageContent;
        -                        $imageContent = undef;
        -                        };
        -                    }
        -
        -                # Use only the text for tooltips and summaries.
        -                else
        -                    {
        -                    $text =~ s{<img mode=\"link\" target=\"[^\"]*\" original=\"([^\"]*)\">}{$1}g;
        -                    };
        -                };
        -
        -            # Convert quotes to fancy quotes.  This has to be done before links because some of them may have JavaScript
        -            # attributes that use the apostrophe character.
        -            $text =~ s/^\'/&lsquo;/gm;
        -            $text =~ s/([\ \(\[\{])\'/$1&lsquo;/g;
        -            $text =~ s/\'/&rsquo;/g;
        -
        -            $text =~ s/^&quot;/&ldquo;/gm;
        -            $text =~ s/([\ \(\[\{])&quot;/$1&ldquo;/g;
        -            $text =~ s/&quot;/&rdquo;/g;
        -
        -            # Resolve and convert links, except for tooltips.
        -            if ($style != NDMARKUPTOHTML_TOOLTIP)
        -                {
        -                $text =~ s{<link target=\"([^\"]*)\" name=\"([^\"]*)\" original=\"([^\"]*)\">}
        -                               {$self->BuildTextLink($1, $2, $3, $package, $using, $sourceFile)}ge;
        -                $text =~ s/<url target=\"([^\"]*)\" name=\"([^\"]*)\">/$self->BuildURLLink($1, $2)/ge;
        -                }
        -            else
        -                {
        -                $text =~ s{<link target=\"[^\"]*\" name=\"([^\"]*)\" original=\"[^\"]*\">}{$1}g;
        -                $text =~ s{<url target=\"[^\"]*\" name=\"([^\"]*)\">}{$1}g;
        -                };
        -
        -            # We do full e-mail links anyway just so the obfuscation remains.
        -            $text =~ s/<email target=\"([^\"]*)\" name=\"([^\"]*)\">/$self->BuildEMailLink($1, $2)/ge;
        -
        -
        -            # Convert inline images, but only for the general style.
        -            if ($style == NDMARKUPTOHTML_GENERAL)
        -                {
        -                $text =~ s{<img mode=\"inline\" target=\"([^\"]*)\" original=\"([^\"]*)\">}
        -                               {$self->BuildImage($sourceFile, 'inline', $1, $2)}ge;
        -                }
        -            else
        -                {
        -                $text =~ s{<img mode=\"inline\" target=\"[^\"]*\" original=\"([^\"]*)\">}{$1}g;
        -                };
        -
        -            # Copyright symbols.  Prevent conversion when part of (a), (b), (c) lists.
        -            if ($text !~ /\(a\)/i)
        -                {  $text =~ s/\(c\)/&copy;/gi;  };
        -
        -            # Trademark symbols.
        -            $text =~ s/\(tm\)/&trade;/gi;
        -            $text =~ s/\(r\)/&reg;/gi;
        -
        -            # Add double spaces too.
        -            $text = $self->AddDoubleSpaces($text);
        -
        -            # Headings
        -            $text =~ s/<h>/<h4 class=CHeading>/g;
        -            $text =~ s/<\/h>/<\/h4>/g;
        -
        -            # Description Lists
        -            $text =~ s/<dl>/<table border=0 cellspacing=0 cellpadding=0 class=CDescriptionList>/g;
        -            $text =~ s/<\/dl>/<\/table>/g;
        -
        -            $text =~ s/<de>/<tr><td class=CDLEntry>/g;
        -            $text =~ s/<\/de>/<\/td>/g;
        -
        -            if ($dlSymbolBehavior == ::ENUM_GLOBAL())
        -                {  $text =~ s/<ds>([^<]+)<\/ds>/$self->MakeDescriptionListSymbol(undef, $1)/ge;  }
        -            elsif ($dlSymbolBehavior == ::ENUM_UNDER_PARENT())
        -                {  $text =~ s/<ds>([^<]+)<\/ds>/$self->MakeDescriptionListSymbol($package, $1)/ge;  }
        -            else # ($dlSymbolBehavior == ::ENUM_UNDER_TYPE())
        -                {  $text =~ s/<ds>([^<]+)<\/ds>/$self->MakeDescriptionListSymbol($symbol, $1)/ge;  }
        -
        -            sub MakeDescriptionListSymbol #(package, text)
        -                {
        -                my ($self, $package, $text) = @_;
        -
        -                $text = NaturalDocs::NDMarkup->RestoreAmpChars($text);
        -                my $symbol = NaturalDocs::SymbolString->FromText($text);
        -
        -                if (defined $package)
        -                    {  $symbol = NaturalDocs::SymbolString->Join($package, $symbol);  };
        -
        -                return
        -                '<tr>'
        -                    . '<td class=CDLEntry>'
        -                        # The anchors are closed, but not around the text, to prevent the :hover CSS style from kicking in.
        -                        . '<a name="' . $self->SymbolToHTMLSymbol($symbol) . '"></a>'
        -                        . $text
        -                    . '</td>';
        -                };
        -
        -            $text =~ s/<dd>/<td class=CDLDescription>/g;
        -            $text =~ s/<\/dd>/<\/td><\/tr>/g;
        -
        -            $output .= $text;
        -            };
        -        };
        -
        -    return $output;
        -    };
        -
        -
        -#
        -#   Function: BuildTextLink
        -#
        -#   Creates a HTML link to a symbol, if it exists.
        -#
        -#   Parameters:
        -#
        -#       target  - The link text.
        -#       name - The link name.
        -#       original - The original text as it appears in the source.
        -#       package  - The package <SymbolString> the link appears in, or undef if none.
        -#       using - An arrayref of additional scope <SymbolStrings> the link has access to, or undef if none.
        -#       sourceFile  - The <FileName> the link appears in.
        -#
        -#       Target, name, and original are assumed to still have <NDMarkup> amp chars.
        -#
        -#   Returns:
        -#
        -#       The link in HTML, including tags.  If the link doesn't resolve to anything, returns the HTML that should be substituted for it.
        -#
        -sub BuildTextLink #(target, name, original, package, using, sourceFile)
        -    {
        -    my ($self, $target, $name, $original, $package, $using, $sourceFile) = @_;
        -
        -    my $plainTarget = $self->RestoreAmpChars($target);
        -
        -    my $symbol = NaturalDocs::SymbolString->FromText($plainTarget);
        -    my $symbolTarget = NaturalDocs::SymbolTable->References(::REFERENCE_TEXT(), $symbol, $package, $using, $sourceFile);
        -
        -    if (defined $symbolTarget)
        -        {
        -        my $symbolTargetFile;
        -
        -        if ($symbolTarget->File() ne $sourceFile)
        -            {
        -            $symbolTargetFile = $self->MakeRelativeURL( $self->OutputFileOf($sourceFile),
        -                                                                               $self->OutputFileOf($symbolTarget->File()), 1 );
        -            };
        -        # else leave it undef
        -
        -        my $symbolTargetTooltipID = $self->BuildToolTip($symbolTarget->Symbol(), $sourceFile, $symbolTarget->Type(),
        -                                                                                 $symbolTarget->Prototype(), $symbolTarget->Summary());
        -
        -        my $toolTipProperties = $self->BuildToolTipLinkProperties($symbolTargetTooltipID);
        -
        -        return '<a href="' . $symbolTargetFile . '#' . $self->SymbolToHTMLSymbol($symbolTarget->Symbol()) . '" '
        -                    . 'class=L' . NaturalDocs::Topics->NameOfType($symbolTarget->Type(), 0, 1) . ' ' . $toolTipProperties . '>'
        -                        . $name
        -                    . '</a>';
        -        }
        -    else
        -        {
        -        return $original;
        -        };
        -    };
        -
        -
        -#
        -#   Function: BuildURLLink
        -#
        -#   Creates a HTML link to an external URL.  Long URLs will have hidden breaks to allow them to wrap.
        -#
        -#   Parameters:
        -#
        -#       target - The URL to link to.
        -#       name - The label of the link.
        -#
        -#       Both are assumed to still have <NDMarkup> amp chars.
        -#
        -#   Returns:
        -#
        -#       The HTML link, complete with tags.
        -#
        -sub BuildURLLink #(target, name)
        -    {
        -    my ($self, $target, $name) = @_;
        -
        -    # Don't restore amp chars on the target.
        -
        -    if (length $name < 50 || $name ne $target)
        -        {  return '<a href="' . $target . '" class=LURL target=_top>' . $name . '</a>';  };
        -
        -    my @segments = split(/([\,\/]|&amp;)/, $target);
        -    my $output = '<a href="' . $target . '" class=LURL target=_top>';
        -
        -    # Get past the first batch of slashes, since we don't want to break on things like http://.
        -
        -    $output .= $segments[0];
        -
        -    my $i = 1;
        -    while ($i < scalar @segments && ($segments[$i] eq '/' || !$segments[$i]))
        -        {
        -        $output .= $segments[$i];
        -        $i++;
        -        };
        -
        -    # Now break on each one of those symbols.
        -
        -    while ($i < scalar @segments)
        -        {
        -        if ($segments[$i] eq ',' || $segments[$i] eq '/' || $segments[$i] eq '&amp;')
        -            {  $output .= '<wbr>';  };
        -
        -        $output .= $segments[$i];
        -        $i++;
        -        };
        -
        -    $output .= '</a>';
        -    return $output;
        -    };
        -
        -
        -#
        -#   Function: BuildEMailLink
        -#
        -#   Creates a HTML link to an e-mail address.  The address will be transparently munged to protect it (hopefully) from spambots.
        -#
        -#   Parameters:
        -#
        -#       target  - The e-mail address.
        -#       name - The label of the link.
        -#
        -#       Both are assumed to still have <NDMarkup> amp chars.
        -#
        -#   Returns:
        -#
        -#       The HTML e-mail link, complete with tags.
        -#
        -sub BuildEMailLink #(target, name)
        -    {
        -    my ($self, $target, $name) = @_;
        -    my @splitAddress;
        -
        -
        -    # Hack the address up.  We want two user pieces and two host pieces.
        -
        -    my ($user, $host) = split(/\@/, $self->RestoreAmpChars($target));
        -
        -    my $userSplit = length($user) / 2;
        -
        -    push @splitAddress, NaturalDocs::NDMarkup->ConvertAmpChars( substr($user, 0, $userSplit) );
        -    push @splitAddress, NaturalDocs::NDMarkup->ConvertAmpChars( substr($user, $userSplit) );
        -
        -    push @splitAddress, '@';
        -
        -    my $hostSplit = length($host) / 2;
        -
        -    push @splitAddress, NaturalDocs::NDMarkup->ConvertAmpChars( substr($host, 0, $hostSplit) );
        -    push @splitAddress, NaturalDocs::NDMarkup->ConvertAmpChars( substr($host, $hostSplit) );
        -
        -
        -    # Now put it back together again.  We'll use spans to split the text transparently and JavaScript to split and join the link.
        -
        -    my $output =
        -    "<a href=\"#\" onClick=\"location.href='mai' + 'lto:' + '" . join("' + '", @splitAddress) . "'; return false;\" class=LEMail>";
        -
        -    if ($name eq $target)
        -        {
        -        $output .=
        -        $splitAddress[0] . '<span style="display: none">.nosp@m.</span>' . $splitAddress[1]
        -        . '<span>@</span>'
        -        . $splitAddress[3] . '<span style="display: none">.nosp@m.</span>' . $splitAddress[4];
        -        }
        -    else
        -        {  $output .= $name;  };
        -
        -    $output .= '</a>';
        -    return $output;
        -    };
        -
        -
        -#
        -#   Function: BuildImage
        -#
        -#   Builds the HTML for an image.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The source <FileName> this image appears in.
        -#       mode - Either "inline" or "link".
        -#       target - The target.
        -#       original - The original text.
        -#
        -#       All are assumed to still have <NDMarkup> amp chars.
        -#
        -#   Returns:
        -#
        -#       The result in HTML.  If the mode was "link", the target image's HTML is added to <imageContent>.
        -#
        -sub BuildImage #(sourceFile, mode, target, original)
        -    {
        -    my ($self, $sourceFile, $mode, $target, $original) = @_;
        -
        -    my $targetNoAmp = $self->RestoreAmpChars($target);
        -
        -    my $image = NaturalDocs::ImageReferenceTable->GetReferenceTarget($sourceFile, $targetNoAmp);
        -
        -    if ($image)
        -        {
        -        my ($width, $height) = NaturalDocs::Project->ImageFileDimensions($image);
        -
        -        if ($mode eq 'inline')
        -            {
        -            return
        -            '<img src="' . $self->MakeRelativeURL($self->OutputFileOf($sourceFile),
        -                                                                       $self->OutputImageOf($image), 1) . '"'
        -
        -            . ($width && $height ? ' width="' . $width . '" height="' . $height . '"' : '')
        -            . '>';
        -            }
        -        else # link
        -            {
        -            # Make the text a little more friendly in the output by removing any folders and file extensions.
        -            # (see images/Table1.gif) will be turned into (see Table1).
        -            my $originalNoAmp = $self->RestoreAmpChars($original);
        -            my $targetIndex = index($originalNoAmp, $targetNoAmp);
        -            my ($shortTarget, $shortTargetNoAmp, $shortOriginal);
        -
        -            if ($targetIndex != -1)
        -                {
        -                $shortTargetNoAmp = (NaturalDocs::File->SplitPath($targetNoAmp))[2];
        -                $shortTargetNoAmp = NaturalDocs::File->NoExtension($shortTargetNoAmp);
        -
        -                substr($originalNoAmp, $targetIndex, length($targetNoAmp), $shortTargetNoAmp);
        -
        -                $shortOriginal = NaturalDocs::NDMarkup->ConvertAmpChars($originalNoAmp);
        -                $shortTarget = NaturalDocs::NDMarkup->ConvertAmpChars($shortTargetNoAmp);
        -                };
        -
        -            my $output =
        -            '<a href="#Image' . $imageAnchorNumber . '" class=CImageLink>'
        -                . ($shortOriginal || $original)
        -            . '</a>';
        -
        -            $imageContent .=
        -            '<blockquote>'
        -            . '<div class=CImage>'
        -                . '<a name="Image' . $imageAnchorNumber . '"></a>'
        -                . '<div class=CImageCaption>' . ($shortTarget || $target) . '</div>'
        -                . '<img src="' . $self->MakeRelativeURL($self->OutputFileOf($sourceFile),
        -                                                                           $self->OutputImageOf($image), 1) . '"'
        -
        -                . ($width && $height ? ' width="' . $width . '" height="' . $height . '"' : '')
        -                . '>'
        -
        -            . '</div></blockquote>';
        -
        -            $imageAnchorNumber++;
        -            return $output;
        -            };
        -        }
        -    else # !$image
        -        {
        -        if ($mode eq 'inline')
        -            {  return '<p>' . $original . '</p>';  }
        -        else #($mode eq 'link')
        -            {  return $original;  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: BuildToolTipLinkProperties
        -#
        -#   Returns the properties that should go in the link tag to add a tooltip to it.  Because the function accepts undef, you can
        -#   call it without checking if <BuildToolTip()> returned undef or not.
        -#
        -#   Parameters:
        -#
        -#       toolTipID - The ID of the tooltip.  If undef, the function will return undef.
        -#
        -#   Returns:
        -#
        -#       The properties that should be put in the link tag, or undef if toolTipID wasn't specified.
        -#
        -sub BuildToolTipLinkProperties #(toolTipID)
        -    {
        -    my ($self, $toolTipID) = @_;
        -
        -    if (defined $toolTipID)
        -        {
        -        my $currentNumber = $tooltipLinkNumber;
        -        $tooltipLinkNumber++;
        -
        -        return 'id=link' . $currentNumber . ' '
        -                . 'onMouseOver="ShowTip(event, \'' . $toolTipID . '\', \'link' . $currentNumber . '\')" '
        -                . 'onMouseOut="HideTip(\'' . $toolTipID . '\')"';
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: AddDoubleSpaces
        -#
        -#   Adds second spaces after the appropriate punctuation with &nbsp; so they show up in HTML.  They don't occur if there isn't at
        -#   least one space after the punctuation, so things like class.member notation won't be affected.
        -#
        -#   Parameters:
        -#
        -#       text - The text to convert.
        -#
        -#   Returns:
        -#
        -#       The text with double spaces as necessary.
        -#
        -sub AddDoubleSpaces #(text)
        -    {
        -    my ($self, $text) = @_;
        -
        -    # Question marks and exclamation points get double spaces unless followed by a lowercase letter.
        -
        -    $text =~ s/  ([^\ \t\r\n] [\!\?])  # Must appear after a non-whitespace character to apply.
        -
        -                      (&quot;|&[lr][sd]quo;|[\'\"\]\}\)]?)  # Tolerate closing quotes, parenthesis, etc.
        -                      ((?:<[^>]+>)*)  # Tolerate tags
        -
        -                      \   # The space
        -                      (?![a-z])  # Not followed by a lowercase character.
        -
        -                   /$1$2$3&nbsp;\ /gx;
        -
        -
        -    # Periods get double spaces if it's not followed by a lowercase letter.  However, if it's followed by a capital letter and the
        -    # preceding word is in the list of acceptable abbreviations, it won't get the double space.  Yes, I do realize I am seriously
        -    # over-engineering this.
        -
        -    $text =~ s/  ([^\ \t\r\n]+)  # The word prior to the period.
        -
        -                      \.
        -
        -                      (&quot;|&[lr][sd]quo;|[\'\"\]\}\)]?)  # Tolerate closing quotes, parenthesis, etc.
        -                      ((?:<[^>]+>)*)  # Tolerate tags
        -
        -                      \   # The space
        -                      ([^a-z])   # The next character, if it's not a lowercase letter.
        -
        -                  /$1 . '.' . $2 . $3 . MaybeExpand($1, $4) . $4/gex;
        -
        -    sub MaybeExpand #(leadWord, nextLetter)
        -        {
        -        my ($leadWord, $nextLetter) = @_;
        -
        -        if ($nextLetter =~ /^[A-Z]$/ && exists $abbreviations{ lc($leadWord) } )
        -            { return ' '; }
        -        else
        -            { return '&nbsp; '; };
        -        };
        -
        -    return $text;
        -    };
        -
        -
        -#
        -#   Function: ConvertAmpChars
        -#
        -#   Converts certain characters to their HTML amp char equivalents.
        -#
        -#   Parameters:
        -#
        -#       text - The text to convert.
        -#
        -#   Returns:
        -#
        -#       The converted text.
        -#
        -sub ConvertAmpChars #(text)
        -    {
        -    my ($self, $text) = @_;
        -
        -    $text =~ s/&/&amp;/g;
        -    $text =~ s/\"/&quot;/g;
        -    $text =~ s/</&lt;/g;
        -    $text =~ s/>/&gt;/g;
        -
        -    return $text;
        -    };
        -
        -
        -#
        -#   Function: RestoreAmpChars
        -#
        -#   Restores all amp characters to their original state.  This works with both <NDMarkup> amp chars and fancy quotes.
        -#
        -#   Parameters:
        -#
        -#       text - The text to convert.
        -#
        -#   Returns:
        -#
        -#       The converted text.
        -#
        -sub RestoreAmpChars #(text)
        -    {
        -    my ($self, $text) = @_;
        -
        -    $text = NaturalDocs::NDMarkup->RestoreAmpChars($text);
        -    $text =~ s/&[lr]squo;/\'/g;
        -    $text =~ s/&[lr]dquo;/\"/g;
        -
        -    return $text;
        -    };
        -
        -
        -#
        -#   Function: AddHiddenBreaks
        -#
        -#   Adds hidden breaks to symbols.  Puts them after symbol and directory separators so long names won't screw up the layout.
        -#
        -#   Parameters:
        -#
        -#       string - The string to break.
        -#
        -#   Returns:
        -#
        -#       The string with hidden breaks.
        -#
        -sub AddHiddenBreaks #(string)
        -    {
        -    my ($self, $string) = @_;
        -
        -    # \.(?=.{5,}) instead of \. so file extensions don't get breaks.
        -    # :+ instead of :: because Mac paths are separated by a : and we want to get those too.
        -
        -    $string =~ s/(\w(?:\.(?=.{5,})|:+|->|\\|\/))(\w)/$1 . '<wbr>' . $2/ge;
        -
        -    return $string;
        -    };
        -
        -
        -#
        -#   Function: FindFirstFile
        -#
        -#   A function that finds and returns the first file entry in the menu, or undef if none.
        -#
        -sub FindFirstFile
        -    {
        -    # Hidden parameter: arrayref
        -    # Used for recursion only.
        -
        -    my ($self, $arrayref) = @_;
        -
        -    if (!defined $arrayref)
        -        {  $arrayref = NaturalDocs::Menu->Content();  };
        -
        -    foreach my $entry (@$arrayref)
        -        {
        -        if ($entry->Type() == ::MENU_FILE())
        -            {
        -            return $entry;
        -            }
        -        elsif ($entry->Type() == ::MENU_GROUP())
        -            {
        -            my $result = $self->FindFirstFile($entry->GroupContent());
        -            if (defined $result)
        -                {  return $result;  };
        -            };
        -        };
        -
        -    return undef;
        -    };
        -
        -
        -#
        -#   Function: ExpandMenu
        -#
        -#   Determines which groups should be expanded.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The source <FileName> to use if you're looking for a source file.
        -#       indexType - The index <TopicType> to use if you're looking for an index.
        -#       selectionHierarchy - The <FileName> the menu is being built for.  Does not have to be on the menu itself.
        -#       rootLength - The length of the menu's root group, *not* including the contents of subgroups.
        -#
        -#   Returns:
        -#
        -#       An arrayref of all the group numbers that should be expanded.  At minimum, it will contain the numbers of the groups
        -#       present in <menuSelectionHierarchy>, though it may contain more.
        -#
        -sub ExpandMenu #(FileName sourceFile, TopicType indexType, NaturalDocs::Menu::Entry[] selectionHierarchy, int rootLength) -> int[] groupsToExpand
        -    {
        -    my ($self, $sourceFile, $indexType, $menuSelectionHierarchy, $rootLength) = @_;
        -
        -    my $toExpand = [ ];
        -
        -
        -    # First expand everything in the selection hierarchy.
        -
        -    my $length = $rootLength;
        -
        -    foreach my $entry (@$menuSelectionHierarchy)
        -        {
        -        $length += $menuGroupLengths{$entry};
        -        push @$toExpand, $menuGroupNumbers{$entry};
        -        };
        -
        -
        -    # Now do multiple passes of group expansion as necessary.  We start from bottomIndex and expand outwards.  We stop going
        -    # in a direction if a group there is too long -- we do not skip over it and check later groups as well.  However, if one direction
        -    # stops, the other can keep going.
        -
        -    my $pass = 1;
        -    my $hasSubGroups;
        -
        -    while ($length < MENU_LENGTH_LIMIT)
        -        {
        -        my $content;
        -        my $topIndex;
        -        my $bottomIndex;
        -
        -
        -        if ($pass == 1)
        -            {
        -            # First pass, we expand the selection's siblings.
        -
        -            if (scalar @$menuSelectionHierarchy)
        -                {  $content = $menuSelectionHierarchy->[0]->GroupContent();  }
        -            else
        -                {  $content = NaturalDocs::Menu->Content();  };
        -
        -            $bottomIndex = 0;
        -
        -            while ($bottomIndex < scalar @$content &&
        -                     !($content->[$bottomIndex]->Type() == ::MENU_FILE() &&
        -                       $content->[$bottomIndex]->Target() eq $sourceFile) &&
        -                     !($content->[$bottomIndex]->Type() != ::MENU_INDEX() &&
        -                       $content->[$bottomIndex]->Target() eq $indexType) )
        -                {  $bottomIndex++;  };
        -
        -            if ($bottomIndex == scalar @$content)
        -                {  $bottomIndex = 0;  };
        -            $topIndex = $bottomIndex - 1;
        -            }
        -
        -        elsif ($pass == 2)
        -            {
        -            # If the section we just expanded had no sub-groups, do another pass trying to expand the parent's sub-groups.  The
        -            # net effect is that groups won't collapse as much unnecessarily.  Someone can click on a file in a sub-group and the
        -            # groups in the parent will stay open.
        -
        -            if (!$hasSubGroups && scalar @$menuSelectionHierarchy)
        -                {
        -                if (scalar @$menuSelectionHierarchy > 1)
        -                    {  $content = $menuSelectionHierarchy->[1]->GroupContent();  }
        -                else
        -                    {  $content = NaturalDocs::Menu->Content();  };
        -
        -                $bottomIndex = 0;
        -
        -                while ($bottomIndex < scalar @$content &&
        -                         $content->[$bottomIndex] != $menuSelectionHierarchy->[0])
        -                    {  $bottomIndex++;  };
        -
        -                $topIndex = $bottomIndex - 1;
        -                $bottomIndex++;  # Increment past our own group.
        -                $hasSubGroups = undef;
        -                }
        -            else
        -                {  last;  };
        -            }
        -
        -        # No more passes.
        -        else
        -            {  last;  };
        -
        -
        -        while ( ($topIndex >= 0 || $bottomIndex < scalar @$content) && $length < MENU_LENGTH_LIMIT)
        -            {
        -            # We do the bottom first.
        -
        -            while ($bottomIndex < scalar @$content && $content->[$bottomIndex]->Type() != ::MENU_GROUP())
        -                {  $bottomIndex++;  };
        -
        -            if ($bottomIndex < scalar @$content)
        -                {
        -                my $bottomEntry = $content->[$bottomIndex];
        -                $hasSubGroups = 1;
        -
        -                if ($length + $menuGroupLengths{$bottomEntry} <= MENU_LENGTH_LIMIT)
        -                    {
        -                    $length += $menuGroupLengths{$bottomEntry};
        -                    push @$toExpand, $menuGroupNumbers{$bottomEntry};
        -                    $bottomIndex++;
        -                    }
        -                else
        -                    {  $bottomIndex = scalar @$content;  };
        -                };
        -
        -            # Top next.
        -
        -            while ($topIndex >= 0 && $content->[$topIndex]->Type() != ::MENU_GROUP())
        -                {  $topIndex--;  };
        -
        -            if ($topIndex >= 0)
        -                {
        -                my $topEntry = $content->[$topIndex];
        -                $hasSubGroups = 1;
        -
        -                if ($length + $menuGroupLengths{$topEntry} <= MENU_LENGTH_LIMIT)
        -                    {
        -                    $length += $menuGroupLengths{$topEntry};
        -                    push @$toExpand, $menuGroupNumbers{$topEntry};
        -                    $topIndex--;
        -                    }
        -                else
        -                    {  $topIndex = -1;  };
        -                };
        -            };
        -
        -
        -        $pass++;
        -        };
        -
        -    return $toExpand;
        -    };
        -
        -
        -#
        -#   Function: GetMenuSelectionHierarchy
        -#
        -#   Finds the sequence of menu groups that contain the current selection.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The source <FileName> to use if you're looking for a source file.
        -#       indexType - The index <TopicType> to use if you're looking for an index.
        -#
        -#   Returns:
        -#
        -#       An arrayref of the <NaturalDocs::Menu::Entry> objects of each group surrounding the selected menu item.  First entry is the
        -#       group immediately encompassing it, and each subsequent entry works its way towards the outermost group.
        -#
        -sub GetMenuSelectionHierarchy #(FileName sourceFile, TopicType indexType) -> NaturalDocs::Menu::Entry[] selectionHierarchy
        -    {
        -    my ($self, $sourceFile, $indexType) = @_;
        -
        -    my $hierarchy = [ ];
        -
        -    $self->FindMenuSelection($sourceFile, $indexType, $hierarchy, NaturalDocs::Menu->Content());
        -
        -    return $hierarchy;
        -    };
        -
        -
        -#
        -#   Function: FindMenuSelection
        -#
        -#   A recursive function that deterimes if it or any of its sub-groups has the menu selection.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The source <FileName> to use if you're looking for a source file.
        -#       indexType - The index <TopicType> to use if you're looking for an index.
        -#       hierarchyRef - A reference to the menu selection hierarchy.
        -#       entries - An arrayref of <NaturalDocs::Menu::Entries> to search.
        -#
        -#   Returns:
        -#
        -#       Whether this group or any of its subgroups had the selection.  If true, it will add any subgroups to the menu selection
        -#       hierarchy but not itself.  This prevents the topmost entry from being added.
        -#
        -sub FindMenuSelection #(FileName sourceFile, TopicType indexType, NaturalDocs::Menu::Entry[] hierarchyRef, NaturalDocs::Menu::Entry[] entries) -> bool hasSelection
        -    {
        -    my ($self, $sourceFile, $indexType, $hierarchyRef, $entries) = @_;
        -
        -    foreach my $entry (@$entries)
        -        {
        -        if ($entry->Type() == ::MENU_GROUP())
        -            {
        -            # If the subgroup has the selection...
        -            if ( $self->FindMenuSelection($sourceFile, $indexType, $hierarchyRef, $entry->GroupContent()) )
        -                {
        -                push @$hierarchyRef, $entry;
        -                return 1;
        -                };
        -            }
        -
        -        elsif ($entry->Type() == ::MENU_FILE())
        -            {
        -            if ($sourceFile eq $entry->Target())
        -                {  return 1;  };
        -            }
        -
        -        elsif ($entry->Type() == ::MENU_INDEX())
        -            {
        -            if ($indexType eq $entry->Target)
        -                {  return 1;  };
        -            };
        -        };
        -
        -    return 0;
        -    };
        -
        -
        -#
        -#   Function: ResetToolTips
        -#
        -#   Resets the <ToolTip Package Variables> for a new page.
        -#
        -#   Parameters:
        -#
        -#       samePage  - Set this flag if there's the possibility that the next batch of tooltips may be on the same page as the last.
        -#
        -sub ResetToolTips #(samePage)
        -    {
        -    my ($self, $samePage) = @_;
        -
        -    if (!$samePage)
        -        {
        -        $tooltipLinkNumber = 1;
        -        $tooltipNumber = 1;
        -        };
        -
        -    $tooltipHTML = undef;
        -    %tooltipSymbolsToNumbers = ( );
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/ClassHierarchy.pm b/vendor/naturaldocs/Modules/NaturalDocs/ClassHierarchy.pm
        deleted file mode 100644
        index 4b01b9a02..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/ClassHierarchy.pm
        +++ /dev/null
        @@ -1,861 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::ClassHierarchy
        -#
        -###############################################################################
        -#
        -#   A package that handles all the gory details of managing the class hierarchy.  It handles the hierarchy itself, which files define
        -#   them, rebuilding the files that are affected by changes, and loading and saving them to a file.
        -#
        -#   Usage and Dependencies:
        -#
        -#       - <NaturalDocs::Settings> and <NaturalDocs::Project> must be initialized before use.
        -#
        -#       - <NaturalDocs::SymbolTable> must be initialized before <Load()> is called.  It must reflect the state as of the last time
        -#          Natural Docs was run.
        -#
        -#       - <Load()> must be called to initialize the package.  At this point, the <Information Functions> will return the state as
        -#         of the last time Natural Docs was run.  You are free to resolve <NaturalDocs::SymbolTable()> afterwards.
        -#
        -#       - <Purge()> must be called, and then <NaturalDocs::Parser->ParseForInformation()> must be called on all files that
        -#         have changed so it can fully resolve the hierarchy via the <Modification Functions()>.  Afterwards the
        -#         <Information Functions> will reflect the current state of the code.
        -#
        -#       - <Save()> must be called to commit any changes to the symbol table back to disk.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -
        -use strict;
        -use integer;
        -
        -use NaturalDocs::ClassHierarchy::Class;
        -use NaturalDocs::ClassHierarchy::File;
        -
        -package NaturalDocs::ClassHierarchy;
        -
        -
        -###############################################################################
        -# Group: Variables
        -
        -#
        -#   handle: CLASS_HIERARCHY_FILEHANDLE
        -#   The file handle used with <ClassHierarchy.nd>.
        -#
        -
        -#
        -#   hash: classes
        -#
        -#   A hash of all the classes.  The keys are the class <SymbolStrings> and the values are <NaturalDocs::ClassHierarchy::Classes>.
        -#
        -my %classes;
        -
        -#
        -#   hash: files
        -#
        -#   A hash of the hierarchy information referenced by file.  The keys are the <FileNames>, and the values are
        -#   <NaturalDocs::ClassHierarchy::File>s.
        -#
        -my %files;
        -
        -#
        -#   hash: parentReferences
        -#
        -#   A hash of all the parent reference strings and what they resolve to.  The keys are the <ReferenceStrings> and the values are
        -#   the class <SymbolStrings> that they resolve to.
        -#
        -my %parentReferences;
        -
        -#
        -#   object: watchedFile
        -#
        -#   A <NaturalDocs::ClassHierarchy::File> object of the file being watched for changes.  This is compared to the version in <files>
        -#   to see if anything was changed since the last parse.
        -#
        -my $watchedFile;
        -
        -#
        -#   string: watchedFileName
        -#
        -#   The <FileName> of the watched file, if any.  If there is no watched file, this will be undef.
        -#
        -my $watchedFileName;
        -
        -#
        -#   bool: dontRebuildFiles
        -#
        -#   A bool to set if you don't want changes in the hierarchy to cause files to be rebuilt.
        -#
        -my $dontRebuildFiles;
        -
        -
        -
        -###############################################################################
        -# Group: Files
        -
        -
        -#
        -#   File: ClassHierarchy.nd
        -#
        -#   Stores the class hierarchy on disk.
        -#
        -#   Format:
        -#
        -#       > [BINARY_FORMAT]
        -#       > [VersionInt: app version]
        -#
        -#       The standard <BINARY_FORMAT> and <VersionInt> header.
        -#
        -#       > [SymbolString: class or undef to end]
        -#
        -#       Next we begin a class segment with its <SymbolString>.  These continue until the end of the file.  Only defined classes are
        -#       included.
        -#
        -#       > [UInt32: number of files]
        -#       > [AString16: file] [AString16: file] ...
        -#
        -#       Next there is the number of files that define that class.  It's a UInt32, which seems like overkill, but I could imagine every
        -#       file in a huge C++ project being under the same namespace, and thus contributing its own definition.  It's theoretically
        -#       possible.
        -#
        -#       Following the number is that many file names.  You must remember the index of each file, as they will be important later.
        -#       Indexes start at one because zero has a special meaning.
        -#
        -#       > [UInt8: number of parents]
        -#       > ( [ReferenceString (no type): parent]
        -#       >   [UInt32: file index] [UInt32: file index] ... [UInt32: 0] ) ...
        -#
        -#       Next there is the number of parents defined for this class.  For each one, we define a parent segment, which consists of
        -#       its <ReferenceString>, and then a zero-terminated string of indexes of the files that define that parent as part of that class.
        -#       The indexes start at one, and are into the list of files we saw previously.
        -#
        -#       Note that we do store class segments for classes without parents, but not for undefined classes.
        -#
        -#       This concludes a class segment.  These segments continue until an undef <SymbolString>.
        -#
        -#   See Also:
        -#
        -#       <File Format Conventions>
        -#
        -#   Revisions:
        -#
        -#       1.22:
        -#
        -#           - Classes and parents switched from AString16s to <SymbolStrings> and <ReferenceStrings>.
        -#           - A ending undef <SymbolString> was added to the end.  Previously it stopped when the file ran out.
        -#
        -#       1.2:
        -#
        -#           - This file was introduced in 1.2.
        -#
        -
        -
        -###############################################################################
        -# Group: File Functions
        -
        -
        -#
        -#   Function: Load
        -#
        -#   Loads the class hierarchy from disk.
        -#
        -sub Load
        -    {
        -    my ($self) = @_;
        -
        -    $dontRebuildFiles = 1;
        -
        -    my $fileIsOkay;
        -    my $fileName = NaturalDocs::Project->DataFile('ClassHierarchy.nd');
        -
        -    if (!NaturalDocs::Settings->RebuildData() && open(CLASS_HIERARCHY_FILEHANDLE, '<' . $fileName))
        -        {
        -        # See if it's binary.
        -        binmode(CLASS_HIERARCHY_FILEHANDLE);
        -
        -        my $firstChar;
        -        read(CLASS_HIERARCHY_FILEHANDLE, $firstChar, 1);
        -
        -        if ($firstChar != ::BINARY_FORMAT())
        -            {
        -            close(CLASS_HIERARCHY_FILEHANDLE);
        -            }
        -        else
        -            {
        -            my $version = NaturalDocs::Version->FromBinaryFile(\*CLASS_HIERARCHY_FILEHANDLE);
        -
        -            # Minor bugs were fixed in 1.33 that may affect the stored data.
        -
        -            if (NaturalDocs::Version->CheckFileFormat( $version, NaturalDocs::Version->FromString('1.33') ))
        -                {  $fileIsOkay = 1;  }
        -            else
        -                {  close(CLASS_HIERARCHY_FILEHANDLE);  };
        -            };
        -        };
        -
        -
        -    if (!$fileIsOkay)
        -        {
        -        NaturalDocs::Project->ReparseEverything();
        -        }
        -    else
        -        {
        -        my $raw;
        -
        -        for (;;)
        -            {
        -            # [SymbolString: class or undef to end]
        -
        -            my $class = NaturalDocs::SymbolString->FromBinaryFile(\*CLASS_HIERARCHY_FILEHANDLE);
        -
        -            if (!defined $class)
        -                {  last;  };
        -
        -            # [UInt32: number of files]
        -
        -            read(CLASS_HIERARCHY_FILEHANDLE, $raw, 4);
        -            my $numberOfFiles = unpack('N', $raw);
        -
        -            my @files;
        -
        -            while ($numberOfFiles)
        -                {
        -                # [AString16: file]
        -
        -                read(CLASS_HIERARCHY_FILEHANDLE, $raw, 2);
        -                my $fileLength = unpack('n', $raw);
        -
        -                my $file;
        -                read(CLASS_HIERARCHY_FILEHANDLE, $file, $fileLength);
        -
        -                push @files, $file;
        -                $self->AddClass($file, $class, NaturalDocs::Languages->LanguageOf($file)->Name());
        -
        -                $numberOfFiles--;
        -                };
        -
        -            # [UInt8: number of parents]
        -
        -            read(CLASS_HIERARCHY_FILEHANDLE, $raw, 1);
        -            my $numberOfParents = unpack('C', $raw);
        -
        -            while ($numberOfParents)
        -                {
        -                # [ReferenceString (no type): parent]
        -
        -                my $parent = NaturalDocs::ReferenceString->FromBinaryFile(\*CLASS_HIERARCHY_FILEHANDLE,
        -                                                                                                         ::BINARYREF_NOTYPE(),
        -                                                                                                         ::REFERENCE_CH_PARENT());
        -
        -                for (;;)
        -                    {
        -                    # [UInt32: file index or 0]
        -
        -                    read(CLASS_HIERARCHY_FILEHANDLE, $raw, 4);
        -                    my $fileIndex = unpack('N', $raw);
        -
        -                    if ($fileIndex == 0)
        -                        {  last;  }
        -
        -                    $self->AddParentReference( $files[$fileIndex - 1], $class, $parent );
        -                    };
        -
        -                $numberOfParents--;
        -                };
        -            };
        -
        -        close(CLASS_HIERARCHY_FILEHANDLE);
        -        };
        -
        -    $dontRebuildFiles = undef;
        -    };
        -
        -
        -#
        -#   Function: Save
        -#
        -#   Saves the class hierarchy to disk.
        -#
        -sub Save
        -    {
        -    my ($self) = @_;
        -
        -    open (CLASS_HIERARCHY_FILEHANDLE, '>' . NaturalDocs::Project->DataFile('ClassHierarchy.nd'))
        -        or die "Couldn't save " . NaturalDocs::Project->DataFile('ClassHierarchy.nd') . ".\n";
        -
        -    binmode(CLASS_HIERARCHY_FILEHANDLE);
        -
        -    print CLASS_HIERARCHY_FILEHANDLE '' . ::BINARY_FORMAT();
        -    NaturalDocs::Version->ToBinaryFile(\*CLASS_HIERARCHY_FILEHANDLE, NaturalDocs::Settings->AppVersion());
        -
        -    while (my ($class, $classObject) = each %classes)
        -        {
        -        if ($classObject->IsDefined())
        -            {
        -            # [SymbolString: class or undef to end]
        -
        -            NaturalDocs::SymbolString->ToBinaryFile(\*CLASS_HIERARCHY_FILEHANDLE, $class);
        -
        -            # [UInt32: number of files]
        -
        -            my @definitions = $classObject->Definitions();
        -            my %definitionIndexes;
        -
        -            print CLASS_HIERARCHY_FILEHANDLE pack('N', scalar @definitions);
        -
        -            for (my $i = 0; $i < scalar @definitions; $i++)
        -                {
        -                # [AString16: file]
        -                print CLASS_HIERARCHY_FILEHANDLE pack('nA*', length($definitions[$i]), $definitions[$i]);
        -                $definitionIndexes{$definitions[$i]} = $i + 1;
        -                };
        -
        -            # [UInt8: number of parents]
        -
        -            my @parents = $classObject->ParentReferences();
        -            print CLASS_HIERARCHY_FILEHANDLE pack('C', scalar @parents);
        -
        -            foreach my $parent (@parents)
        -                {
        -                # [ReferenceString (no type): parent]
        -
        -                NaturalDocs::ReferenceString->ToBinaryFile(\*CLASS_HIERARCHY_FILEHANDLE, $parent, ::BINARYREF_NOTYPE());
        -
        -                # [UInt32: file index]
        -
        -                my @parentDefinitions = $classObject->ParentReferenceDefinitions($parent);
        -
        -                foreach my $parentDefinition (@parentDefinitions)
        -                    {
        -                    print CLASS_HIERARCHY_FILEHANDLE pack('N', $definitionIndexes{$parentDefinition});
        -                    };
        -
        -                # [UInt32: 0]
        -                print CLASS_HIERARCHY_FILEHANDLE pack('N', 0);
        -                };
        -            };
        -        };
        -
        -    # [SymbolString: class or undef to end]
        -
        -    NaturalDocs::SymbolString->ToBinaryFile(\*CLASS_HIERARCHY_FILEHANDLE, undef);
        -
        -    close(CLASS_HIERARCHY_FILEHANDLE);
        -    };
        -
        -
        -#
        -#   Function: Purge
        -#
        -#   Purges the hierarchy of files that no longer have Natural Docs content.
        -#
        -sub Purge
        -    {
        -    my ($self) = @_;
        -
        -    my $filesToPurge = NaturalDocs::Project->FilesToPurge();
        -
        -    foreach my $file (keys %$filesToPurge)
        -        {
        -        $self->DeleteFile($file);
        -        };
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Interface Functions
        -
        -
        -#
        -#   Function: OnInterpretationChange
        -#
        -#   Called by <NaturalDocs::SymbolTable> whenever a class hierarchy reference's intepretation changes, meaning it switched
        -#   from one symbol to another.
        -#
        -#       reference - The <ReferenceString> whose current interpretation changed.
        -#
        -sub OnInterpretationChange #(reference)
        -    {
        -    my ($self, $reference) = @_;
        -
        -    if (NaturalDocs::ReferenceString->TypeOf($reference) == ::REFERENCE_CH_PARENT())
        -        {
        -        # The approach here is simply to completely delete the reference and readd it.  This is less than optimal efficiency, since it's
        -        # being removed and added from %files too, even though that isn't required.  However, the simpler code is worth it
        -        # considering this will only happen when a parent reference becomes defined or undefined, or on the rare languages (like C#)
        -        # that allow relative parent references.
        -
        -        my $oldTargetSymbol = $parentReferences{$reference};
        -        my $oldTargetObject = $classes{$oldTargetSymbol};
        -
        -        my @classesWithReferenceParent = $oldTargetObject->Children();
        -
        -        # Each entry is an arrayref of file names.  Indexes are the same as classesWithReferenceParent's.
        -        my @filesDefiningReferenceParent;
        -
        -        foreach my $classWithReferenceParent (@classesWithReferenceParent)
        -            {
        -            my $fileList = [ $classes{$classWithReferenceParent}->ParentReferenceDefinitions($reference) ];
        -            push @filesDefiningReferenceParent, $fileList;
        -
        -            foreach my $fileDefiningReferenceParent (@$fileList)
        -                {
        -                $self->DeleteParentReference($fileDefiningReferenceParent, $classWithReferenceParent, $reference);
        -                };
        -            };
        -
        -
        -        # This will force the reference to be reinterpreted on the next add.
        -
        -        delete $parentReferences{$reference};
        -
        -
        -        # Now we can just readd it.
        -
        -        for (my $i = 0; $i < scalar @classesWithReferenceParent; $i++)
        -            {
        -            foreach my $file (@{$filesDefiningReferenceParent[$i]})
        -                {
        -                $self->AddParentReference($file, $classesWithReferenceParent[$i], $reference);
        -                };
        -            };
        -        };
        -
        -    # The only way for a REFERENCE_CH_CLASS reference to change is if the symbol is deleted.  That will be handled by
        -    # <AnalyzeChanges()>, so we don't need to do anything here.
        -    };
        -
        -
        -#
        -#   Function: OnTargetSymbolChange
        -#
        -#   Called by <NaturalDocs::SymbolTable> whenever a class hierarchy reference's target symbol changes, but the reference
        -#   still resolves to the same symbol.
        -#
        -#   Parameters:
        -#
        -#       reference - The <ReferenceString> that was affected by the change.
        -#
        -sub OnTargetSymbolChange #(reference)
        -    {
        -    my ($self, $reference) = @_;
        -
        -    my $type = NaturalDocs::ReferenceString->TypeOf($reference);
        -    my $class;
        -
        -    if ($type == ::REFERENCE_CH_PARENT())
        -        {  $class = $parentReferences{$reference};  }
        -    else # ($type == ::REFERENCE_CH_CLASS())
        -        {
        -        # Class references are global absolute, so we can just yank the symbol.
        -        (undef, $class, undef, undef, undef, undef) = NaturalDocs::ReferenceString->InformationOf($reference);
        -        };
        -
        -    $self->RebuildFilesFor($class, 1, 0, 1);
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Modification Functions
        -
        -
        -#
        -#   Function: AddClass
        -#
        -#   Adds a class to the hierarchy.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName> the class was defined in.
        -#       class - The class <SymbolString>.
        -#       languageName - The name of the language this applies to.
        -#
        -#   Note:
        -#
        -#       The file parameter must be defined when using this function externally.  It may be undef for internal use only.
        -#
        -sub AddClass #(file, class, languageName)
        -    {
        -    my ($self, $file, $class, $languageName) = @_;
        -
        -    if (!exists $classes{$class})
        -        {
        -        $classes{$class} = NaturalDocs::ClassHierarchy::Class->New();
        -        NaturalDocs::SymbolTable->AddReference($self->ClassReferenceOf($class, $languageName), $file)
        -        };
        -
        -    if (defined $file)
        -        {
        -        # If this was the first definition for this class...
        -        if ($classes{$class}->AddDefinition($file))
        -            {  $self->RebuildFilesFor($class, 1, 1, 1);  };
        -
        -        if (!exists $files{$file})
        -            {  $files{$file} = NaturalDocs::ClassHierarchy::File->New();  };
        -
        -        $files{$file}->AddClass($class);
        -
        -        if (defined $watchedFileName)
        -            {  $watchedFile->AddClass($class);  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: AddParentReference
        -#
        -#   Adds a class-parent relationship to the hierarchy.  The classes will be created if they don't already exist.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName> the reference was defined in.
        -#       class - The class <SymbolString>.
        -#       symbol - The parent class <SymbolString>.
        -#       scope - The package <SymbolString> that the reference appeared in.
        -#       using - An arrayref of package <SymbolStrings> that the reference has access to via "using" statements.
        -#       resolvingFlags - Any <Resolving Flags> to be used when resolving the reference.
        -#
        -#   Alternate Parameters:
        -#
        -#       file - The <FileName> the reference was defined in.
        -#       class - The class <SymbolString>.
        -#       reference - The parent <ReferenceString>.
        -#
        -sub AddParentReference #(file, class, symbol, scope, using, resolvingFlags) or (file, class, reference)
        -    {
        -    my ($self, $file, $class, $symbol, $parentReference);
        -
        -    if (scalar @_ == 7)
        -        {
        -        my ($scope, $using, $resolvingFlags);
        -        ($self, $file, $class, $symbol, $scope, $using, $resolvingFlags) = @_;
        -
        -        $parentReference = NaturalDocs::ReferenceString->MakeFrom(::REFERENCE_CH_PARENT(), $symbol,
        -                                                                                                    NaturalDocs::Languages->LanguageOf($file)->Name(),
        -                                                                                                    $scope, $using, $resolvingFlags);
        -        }
        -    else
        -        {
        -        ($self, $file, $class, $parentReference) = @_;
        -        $symbol = (NaturalDocs::ReferenceString->InformationOf($parentReference))[1];
        -        };
        -
        -
        -    # In case it doesn't already exist.
        -    $self->AddClass($file, $class);
        -
        -    my $parent;
        -    if (exists $parentReferences{$parentReference})
        -        {
        -        $parent = $parentReferences{$parentReference};
        -        }
        -    else
        -        {
        -        NaturalDocs::SymbolTable->AddReference($parentReference, $file);
        -        my $parentTarget = NaturalDocs::SymbolTable->References($parentReference);
        -
        -        if (defined $parentTarget)
        -            {  $parent = $parentTarget->Symbol();  }
        -        else
        -            {  $parent = $symbol;  };
        -
        -        # In case it doesn't already exist.
        -        $self->AddClass(undef, $parent);
        -
        -        $parentReferences{$parentReference} = $parent;
        -        };
        -
        -
        -    # If this defined a new parent...
        -    if ($classes{$class}->AddParentReference($parentReference, $file, \%parentReferences))
        -        {
        -        $classes{$parent}->AddChild($class);
        -
        -        $self->RebuildFilesFor($class, 0, 1, 0);
        -        $self->RebuildFilesFor($parent, 0, 1, 0);
        -        };
        -
        -    $files{$file}->AddParentReference($class, $parentReference);
        -
        -    if (defined $watchedFileName)
        -        {  $watchedFile->AddParentReference($class, $parentReference);  };
        -    };
        -
        -
        -#
        -#   Function: WatchFileForChanges
        -#
        -#   Watches a file for changes, which can then be applied by <AnalyzeChanges()>.  Definitions are not deleted via a DeleteClass()
        -#   function.  Instead, a file is watched for changes, reparsed, and then a comparison is made to look for definitions that
        -#   disappeared and any other relevant changes.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName> to watch.
        -#
        -sub WatchFileForChanges #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    $watchedFile = NaturalDocs::ClassHierarchy::File->New();
        -    $watchedFileName = $file;
        -    };
        -
        -
        -#
        -#   Function: AnalyzeChanges
        -#
        -#   Checks the watched file for any changes that occured since the last time is was parsed, and updates the hierarchy as
        -#   necessary.  Also sends any files that are affected to <NaturalDocs::Project->RebuildFile()>.
        -#
        -sub AnalyzeChanges
        -    {
        -    my ($self) = @_;
        -
        -    # If the file didn't have any classes before, and it still doesn't, it wont be in %files.
        -    if (exists $files{$watchedFileName})
        -        {
        -        my @originalClasses = $files{$watchedFileName}->Classes();
        -
        -        foreach my $originalClass (@originalClasses)
        -            {
        -            # If the class isn't there the second time around...
        -            if (!$watchedFile->HasClass($originalClass))
        -                {  $self->DeleteClass($watchedFileName, $originalClass);  }
        -
        -            else
        -                {
        -                my @originalParents = $files{$watchedFileName}->ParentReferencesOf($originalClass);
        -
        -                foreach my $originalParent (@originalParents)
        -                    {
        -                    # If the parent reference wasn't there the second time around...
        -                    if (!$watchedFile->HasParentReference($originalClass, $originalParent))
        -                        {  $self->DeleteParentReference($watchedFileName, $originalClass, $originalParent);  };
        -                    };
        -                };
        -            };
        -        };
        -
        -
        -    $watchedFile = undef;
        -    $watchedFileName = undef;
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Information Functions
        -
        -
        -#
        -#   Function: ParentsOf
        -#   Returns a <SymbolString> array of the passed class' parents, or an empty array if none.  Note that not all of them may be
        -#   defined.
        -#
        -sub ParentsOf #(class)
        -    {
        -    my ($self, $class) = @_;
        -
        -    if (exists $classes{$class})
        -        {  return $classes{$class}->Parents();  }
        -    else
        -        {  return ( );  };
        -    };
        -
        -#
        -#   Function: ChildrenOf
        -#   Returns a <SymbolString> array of the passed class' children, or an empty array if none.  Note that not all of them may be
        -#   defined.
        -#
        -sub ChildrenOf #(class)
        -    {
        -    my ($self, $class) = @_;
        -
        -    if (exists $classes{$class})
        -        {  return $classes{$class}->Children();  }
        -    else
        -        {  return ( );  };
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -
        -#
        -#   Function: DeleteFile
        -#
        -#   Deletes a file and everything defined in it.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName>.
        -#
        -sub DeleteFile #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    if (!exists $files{$file})
        -        {  return;  };
        -
        -    my @classes = $files{$file}->Classes();
        -    foreach my $class (@classes)
        -        {
        -        $self->DeleteClass($file, $class);
        -        };
        -
        -    delete $files{$file};
        -    };
        -
        -#
        -#   Function: DeleteClass
        -#
        -#   Deletes a class definition from a file.  Will also delete any parent references from this class and file.  Will rebuild any file
        -#   affected unless <dontRebuildFiles> is set.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName> that defines the class.
        -#       class - The class <SymbolString>.
        -#
        -sub DeleteClass #(file, class)
        -    {
        -    my ($self, $file, $class) = @_;
        -
        -    my @parents = $files{$file}->ParentReferencesOf($class);
        -    foreach my $parent (@parents)
        -        {
        -        $self->DeleteParentReference($file, $class, $parent);
        -        };
        -
        -    $files{$file}->DeleteClass($class);
        -
        -    # If we're deleting the last definition of this class.
        -    if ($classes{$class}->DeleteDefinition($file))
        -        {
        -        if (!$classes{$class}->HasChildren())
        -            {
        -            delete $classes{$class};
        -
        -            if (!$dontRebuildFiles)
        -                {  NaturalDocs::Project->RebuildFile($file);  };
        -            }
        -        else
        -            {  $self->RebuildFilesFor($class, 0, 1, 1);  };
        -
        -        };
        -    };
        -
        -
        -#
        -#   Function: DeleteParentReference
        -#
        -#   Deletes a class' parent reference and returns whether it resulted in the loss of a parent class.  Will rebuild any file affected
        -#   unless <dontRebuildFiles> is set.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName> that defines the reference.
        -#       class - The class <SymbolString>.
        -#       reference - The parent <ReferenceString>.
        -#
        -#   Returns:
        -#
        -#       If the class lost a parent as a result of this, it will return its <SymbolString>.  It will return undef otherwise.
        -#
        -sub DeleteParentReference #(file, class, reference)
        -    {
        -    my ($self, $file, $class, $reference) = @_;
        -
        -    if (!exists $classes{$class})
        -        {  return;  };
        -
        -    $files{$file}->DeleteParentReference($class, $reference);
        -
        -    my $deletedParent = $classes{$class}->DeleteParentReference($reference, $file, \%parentReferences);
        -
        -    if (defined $deletedParent)
        -        {
        -        my $deletedParentObject = $classes{$deletedParent};
        -
        -        $deletedParentObject->DeleteChild($class);
        -
        -        $self->RebuildFilesFor($deletedParent, 0, 1, 0);
        -        $self->RebuildFilesFor($class, 0, 1, 0);
        -
        -        if (!$deletedParentObject->HasChildren() && !$deletedParentObject->IsDefined())
        -            {
        -            delete $classes{$deletedParent};
        -            NaturalDocs::SymbolTable->DeleteReference(
        -                $self->ClassReferenceOf($class, NaturalDocs::Languages->LanguageOf($file)->Name()) );
        -            };
        -
        -        return $deletedParent;
        -        };
        -
        -    return undef;
        -    };
        -
        -
        -#
        -#   Function: ClassReferenceOf
        -#
        -#   Returns the <REFERENCE_CH_CLASS> <ReferenceString> of the passed class <SymbolString>.
        -#
        -sub ClassReferenceOf #(class, languageName)
        -    {
        -    my ($self, $class, $languageName) = @_;
        -
        -    return NaturalDocs::ReferenceString->MakeFrom(::REFERENCE_CH_CLASS(), $class, $languageName, undef, undef,
        -                                                                            ::RESOLVE_ABSOLUTE() | ::RESOLVE_NOPLURAL());
        -    };
        -
        -
        -#
        -#   Function: RebuildFilesFor
        -#
        -#   Calls <NaturalDocs::Project->RebuildFile()> for every file defining the passed class, its parents, and/or its children.
        -#   Returns without doing anything if <dontRebuildFiles> is set.
        -#
        -#   Parameters:
        -#
        -#       class - The class <SymbolString>.
        -#       rebuildParents - Whether to rebuild the class' parents.
        -#       rebuildSelf - Whether to rebuild the class.
        -#       rebuildChildren - Whether to rebuild the class' children.
        -#
        -sub RebuildFilesFor #(class, rebuildParents, rebuildSelf, rebuildChildren)
        -    {
        -    my ($self, $class, $rebuildParents, $rebuildSelf, $rebuildChildren) = @_;
        -
        -    if ($dontRebuildFiles)
        -        {  return;  };
        -
        -    my @classesToBuild;
        -
        -    if ($rebuildParents)
        -        {  @classesToBuild = $classes{$class}->Parents();  };
        -    if ($rebuildSelf)
        -        {  push @classesToBuild, $class;  };
        -    if ($rebuildChildren)
        -        {  push @classesToBuild, $classes{$class}->Children();  };
        -
        -    foreach my $classToBuild (@classesToBuild)
        -        {
        -        my @definitions = $classes{$classToBuild}->Definitions();
        -
        -        foreach my $definition (@definitions)
        -            {  NaturalDocs::Project->RebuildFile($definition);  };
        -        };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/ClassHierarchy/Class.pm b/vendor/naturaldocs/Modules/NaturalDocs/ClassHierarchy/Class.pm
        deleted file mode 100644
        index 48ed6e28e..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/ClassHierarchy/Class.pm
        +++ /dev/null
        @@ -1,413 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::ClassHierarchy::Class
        -#
        -###############################################################################
        -#
        -#   An object that stores information about a class in the hierarchy.  It does not store its <SymbolString>; it assumes that it will
        -#   be stored in a hashref where the key is the <SymbolString>.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::ClassHierarchy::Class;
        -
        -
        -#
        -#   Constants: Members
        -#
        -#   The class is implemented as a blessed arrayref.  The keys are the constants below.
        -#
        -#   DEFINITIONS - An existence hashref of all the <FileNames> which define this class.  Undef if none.
        -#   PARENTS - An existence hashref of the <SymbolStrings> of all the parents this class has.
        -#   CHILDREN - An existence hashref of the <SymbolStrings> of all the children this class has.
        -#   PARENT_REFERENCES - A hashref of the parent <ReferenceStrings> this class has.  The keys are the <ReferenceStrings>,
        -#                                      and the values are existence hashrefs of all the <FileNames> that define them.  Undef if none.
        -#
        -use NaturalDocs::DefineMembers 'DEFINITIONS', 'PARENTS', 'CHILDREN', 'PARENT_REFERENCES';
        -# Dependency: New() depends on the order of these constants, as well as the class not being derived from any other.
        -
        -
        -###############################################################################
        -# Group: Modification Functions
        -
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new class.
        -#
        -sub New
        -    {
        -    # Dependency: This function depends on the order of the constants, as well as the class not being derived from any other.
        -    my ($package, $definitionFile) = @_;
        -
        -    my $object = [ undef, undef, undef, undef ];
        -    bless $object, $package;
        -
        -    return $object;
        -    };
        -
        -
        -#
        -#   Function: AddDefinition
        -#
        -#   Adds a rew definition of this class and returns if that was the first definition.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName> the definition appears in.
        -#
        -#   Returns:
        -#
        -#       Whether this was the first definition of this class.
        -#
        -sub AddDefinition #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    my $wasFirst;
        -
        -    if (!defined $self->[DEFINITIONS])
        -        {
        -        $self->[DEFINITIONS] = { };
        -        $wasFirst = 1;
        -        };
        -
        -    $self->[DEFINITIONS]->{$file} = 1;
        -
        -    return $wasFirst;
        -    };
        -
        -
        -#
        -#   Function: DeleteDefinition
        -#
        -#   Removes the definition of this class and returns if there are no more definitions.  Note that if there are no more
        -#   definitions, you may still want to keep the object around if <HasChildren()> returns true.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName> the definition appears in.
        -#
        -#   Returns:
        -#
        -#       Whether this deleted the last definition of this class.
        -#
        -sub DeleteDefinition #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    if (defined $self->[DEFINITIONS])
        -        {
        -        delete $self->[DEFINITIONS]->{$file};
        -
        -        if (!scalar keys %{$self->[DEFINITIONS]})
        -            {
        -            $self->[DEFINITIONS] = undef;
        -            return 1;
        -            };
        -        };
        -
        -    return undef;
        -    };
        -
        -
        -#
        -#   Function: AddParentReference
        -#
        -#   Adds a parent reference to the class and return whether it resulted in a new parent class.
        -#
        -#   Parameters:
        -#
        -#       reference - The <ReferenceString> used to determine the parent.
        -#       file - The <FileName> the parent reference is in.
        -#       referenceTranslations - A hashref of what each reference currently resolves to.  The keys are the
        -#                                         <ReferenceStrings> and the values are class <SymbolStrings>.  It should include an entry for
        -#                                         the reference parameter above.
        -#
        -#   Returns:
        -#
        -#       If the reference adds a new parent, it will return that parent's <SymbolString>.  Otherwise it will return undef.
        -#
        -sub AddParentReference #(reference, file, referenceTranslations)
        -    {
        -    my ($self, $reference, $file, $referenceTranslations) = @_;
        -
        -    if (!defined $self->[PARENT_REFERENCES])
        -        {  $self->[PARENT_REFERENCES] = { };  };
        -    if (!defined $self->[PARENTS])
        -        {  $self->[PARENTS] = { };  };
        -
        -
        -    if (!exists $self->[PARENT_REFERENCES]->{$reference})
        -        {
        -        $self->[PARENT_REFERENCES]->{$reference} = { $file => 1 };
        -
        -        my $symbol = $referenceTranslations->{$reference};
        -
        -        if (!exists $self->[PARENTS]->{$symbol})
        -            {
        -            $self->[PARENTS]->{$symbol} = 1;
        -            return $symbol;
        -            }
        -        else
        -            {  return undef;  };
        -        }
        -    else
        -        {
        -        $self->[PARENT_REFERENCES]->{$reference}->{$file} = 1;
        -        return undef;
        -        };
        -    };
        -
        -#
        -#   Function: DeleteParentReference
        -#
        -#   Deletes a parent reference from the class and return whether it resulted in a loss of a parent class.
        -#
        -#   Parameters:
        -#
        -#       reference - The <ReferenceString> used to determine the parent.
        -#       file - The <FileName> the parent declaration is in.
        -#       referenceTranslations - A hashref of what each reference currently resolves to.  The keys are the
        -#                                         <ReferenceStrings> and the values are class <SymbolStrings>.  It should include an entry for
        -#                                         the reference parameter above.
        -#
        -#   Returns:
        -#
        -#       If this causes a parent class to be lost, it will return that parent's <SymbolString>.  Otherwise it will return undef.
        -#
        -sub DeleteParentReference #(reference, file, referenceTranslations)
        -    {
        -    my ($self, $reference, $file, $referenceTranslations) = @_;
        -
        -    if (defined $self->[PARENT_REFERENCES] && exists $self->[PARENT_REFERENCES]->{$reference} &&
        -        exists $self->[PARENT_REFERENCES]->{$reference}->{$file})
        -        {
        -        delete $self->[PARENT_REFERENCES]->{$reference}->{$file};
        -
        -        # Quit if there are other definitions of this reference.
        -        if (scalar keys %{$self->[PARENT_REFERENCES]->{$reference}})
        -            {  return undef;  };
        -
        -        delete $self->[PARENT_REFERENCES]->{$reference};
        -
        -        if (!scalar keys %{$self->[PARENT_REFERENCES]})
        -            {  $self->[PARENT_REFERENCES] = undef;  };
        -
        -        my $parent = $referenceTranslations->{$reference};
        -
        -        # Check if any other references resolve to the same parent.
        -        if (defined $self->[PARENT_REFERENCES])
        -            {
        -            foreach my $parentReference (keys %{$self->[PARENT_REFERENCES]})
        -                {
        -                if ($referenceTranslations->{$parentReference} eq $parent)
        -                    {  return undef;  };
        -                };
        -            };
        -
        -        # If we got this far, no other parent references resolve to this symbol.
        -
        -        delete $self->[PARENTS]->{$parent};
        -
        -        if (!scalar keys %{$self->[PARENTS]})
        -            {  $self->[PARENTS] = undef;  };
        -
        -        return $parent;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: AddChild
        -#   Adds a child <SymbolString> to the class.  Unlike <AddParentReference()>, this does not keep track of anything other than
        -#   whether it has it or not.
        -#
        -#   Parameters:
        -#
        -#       child - The <SymbolString> to add.
        -#
        -sub AddChild #(child)
        -    {
        -    my ($self, $child) = @_;
        -
        -    if (!defined $self->[CHILDREN])
        -        {  $self->[CHILDREN] = { };  };
        -
        -    $self->[CHILDREN]->{$child} = 1;
        -    };
        -
        -#
        -#   Function: DeleteChild
        -#   Deletes a child <SymbolString> from the class.  Unlike <DeleteParentReference()>, this does not keep track of anything other
        -#   than whether it has it or not.
        -#
        -#   Parameters:
        -#
        -#       child - The <SymbolString> to delete.
        -#
        -sub DeleteChild #(child)
        -    {
        -    my ($self, $child) = @_;
        -
        -    if (defined $self->[CHILDREN])
        -        {
        -        delete $self->[CHILDREN]->{$child};
        -
        -        if (!scalar keys %{$self->[CHILDREN]})
        -            {  $self->[CHILDREN] = undef;  };
        -        };
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Information Functions
        -
        -#
        -#   Function: Definitions
        -#   Returns an array of the <FileNames> that define this class, or an empty array if none.
        -#
        -sub Definitions
        -    {
        -    my ($self) = @_;
        -
        -    if (defined $self->[DEFINITIONS])
        -        {  return keys %{$self->[DEFINITIONS]};  }
        -    else
        -        {  return ( );  };
        -    };
        -
        -#
        -#   Function: IsDefinedIn
        -#   Returns whether the class is defined in the passed <FileName>.
        -#
        -sub IsDefinedIn #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    if (defined $self->[DEFINITIONS])
        -        {  return exists $self->[DEFINITIONS]->{$file};  }
        -    else
        -        {  return 0;  };
        -    };
        -
        -#
        -#   Function: IsDefined
        -#   Returns whether the class is defined in any files.
        -#
        -sub IsDefined
        -    {
        -    my ($self) = @_;
        -    return defined $self->[DEFINITIONS];
        -    };
        -
        -#
        -#   Function: ParentReferences
        -#   Returns an array of the parent <ReferenceStrings>, or an empty array if none.
        -#
        -sub ParentReferences
        -    {
        -    my ($self) = @_;
        -
        -    if (defined $self->[PARENT_REFERENCES])
        -        {  return keys %{$self->[PARENT_REFERENCES]};  }
        -    else
        -        {  return ( );  };
        -    };
        -
        -#
        -#   Function: HasParentReference
        -#   Returns whether the class has the passed parent <ReferenceString>.
        -#
        -sub HasParentReference #(reference)
        -    {
        -    my ($self, $reference) = @_;
        -    return (defined $self->[PARENT_REFERENCES] && exists $self->[PARENT_REFERENCES]->{$reference});
        -    };
        -
        -#
        -#   Function: HasParentReferences
        -#   Returns whether the class has any parent <ReferenceStrings>.
        -#
        -sub HasParentReferences
        -    {
        -    my ($self) = @_;
        -    return defined $self->[PARENT_REFERENCES];
        -    };
        -
        -#
        -#   Function: Parents
        -#   Returns an array of the parent <SymbolStrings>, or an empty array if none.
        -#
        -sub Parents
        -    {
        -    my ($self) = @_;
        -
        -    if (defined $self->[PARENTS])
        -        {  return keys %{$self->[PARENTS]};  }
        -    else
        -        {  return ( );  };
        -    };
        -
        -#
        -#   Function: HasParents
        -#   Returns whether the class has any parent <SymbolStrings> defined.
        -#
        -sub HasParents
        -    {
        -    my ($self) = @_;
        -    return defined $self->[PARENTS];
        -    };
        -
        -#
        -#   Function: Children
        -#   Returns an array of the child <SymbolStrings>, or an empty array if none.
        -#
        -sub Children
        -    {
        -    my ($self) = @_;
        -
        -    if (defined $self->[CHILDREN])
        -        {  return keys %{$self->[CHILDREN]};  }
        -    else
        -        {  return ( );  };
        -    };
        -
        -#
        -#   Function: HasChildren
        -#   Returns whether any child <SymbolStrings> are defined.
        -#
        -sub HasChildren
        -    {
        -    my ($self) = @_;
        -    return defined $self->[CHILDREN];
        -    };
        -
        -
        -#
        -#   Function: ParentReferenceDefinitions
        -#   Returns an array of the <FileNames> which define the passed parent <ReferenceString>, or an empty array if none.
        -#
        -sub ParentReferenceDefinitions #(reference)
        -    {
        -    my ($self, $reference) = @_;
        -
        -    if (defined $self->[PARENT_REFERENCES] && exists $self->[PARENT_REFERENCES]->{$reference})
        -        {  return keys %{$self->[PARENT_REFERENCES]->{$reference}};  }
        -    else
        -        {  return ( );  };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/ClassHierarchy/File.pm b/vendor/naturaldocs/Modules/NaturalDocs/ClassHierarchy/File.pm
        deleted file mode 100644
        index 0f7b3226a..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/ClassHierarchy/File.pm
        +++ /dev/null
        @@ -1,158 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::ClassHierarchy::File
        -#
        -###############################################################################
        -#
        -#   An object that stores information about what hierarchy information is present in a file.  It does not store its <FileName>; it
        -#   assumes that it will be stored in a hashref where the key is the <FileName>.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::ClassHierarchy::File;
        -
        -
        -#
        -#   Topic: Implementation
        -#
        -#   Since there's only one member in the class, and it's a hashref, the class is simply the hashref itself blessed as a class.
        -#   The keys are the class <SymbolStrings> that are defined in the file, and the values are existence hashrefs of each class'
        -#   parent <ReferenceStrings>, or undef if none.
        -#
        -
        -
        -###############################################################################
        -# Group: Modification Functions
        -
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new class.
        -#
        -sub New
        -    {
        -    my ($package) = @_;
        -
        -    my $object = { };
        -    bless $object, $package;
        -
        -    return $object;
        -    };
        -
        -#
        -#   Function: AddClass
        -#   Adds a rew class <SymbolString> to the file.
        -#
        -sub AddClass #(class)
        -    {
        -    my ($self, $class) = @_;
        -
        -    if (!exists $self->{$class})
        -        {  $self->{$class} = undef;  };
        -    };
        -
        -#
        -#   Function: DeleteClass
        -#   Deletes a class <SymbolString> from the file.
        -#
        -sub DeleteClass #(class)
        -    {
        -    my ($self, $class) = @_;
        -    delete $self->{$class};
        -    };
        -
        -#
        -#   Function: AddParentReference
        -#   Adds a parent <ReferenceString> to a class <SymbolString>.
        -#
        -sub AddParentReference #(class, parentReference)
        -    {
        -    my ($self, $class, $parent) = @_;
        -
        -    if (!exists $self->{$class} || !defined $self->{$class})
        -        {  $self->{$class} = { };  };
        -
        -    $self->{$class}->{$parent} = 1;
        -    };
        -
        -#
        -#   Function: DeleteParentReference
        -#   Deletes a parent <ReferenceString> from a class <SymbolString>.
        -#
        -sub DeleteParentReference #(class, parent)
        -    {
        -    my ($self, $class, $parent) = @_;
        -
        -    if (exists $self->{$class})
        -        {
        -        delete $self->{$class}->{$parent};
        -
        -        if (!scalar keys %{$self->{$class}})
        -            {  $self->{$class} = undef;  };
        -        };
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Information Functions
        -
        -
        -#
        -#   Function: Classes
        -#   Returns an array of the class <SymbolStrings> that are defined by this file, or an empty array if none.
        -#
        -sub Classes
        -    {
        -    my ($self) = @_;
        -    return keys %{$self};
        -    };
        -
        -#
        -#   Function: HasClass
        -#   Returns whether the file defines the passed class <SymbolString>.
        -#
        -sub HasClass #(class)
        -    {
        -    my ($self, $class) = @_;
        -    return exists $self->{$class};
        -    };
        -
        -#
        -#   Function: ParentReferencesOf
        -#   Returns an array of the parent <ReferenceStrings> that are defined by the class, or an empty array if none.
        -#
        -sub ParentReferencesOf #(class)
        -    {
        -    my ($self, $class) = @_;
        -
        -    if (!exists $self->{$class} || !defined $self->{$class})
        -        {  return ( );  }
        -    else
        -        {  return keys %{$self->{$class}};  };
        -    };
        -
        -#
        -#   Function: HasParentReference
        -#   Returns whether the file defines the passed class <SymbolString> and parent <ReferenceString>.
        -#
        -sub HasParentReference #(class, parent)
        -    {
        -    my ($self, $class, $parent) = @_;
        -
        -    if (!$self->HasClass($class))
        -        {  return undef;  };
        -
        -    return exists $self->{$class}->{$parent};
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/ConfigFile.pm b/vendor/naturaldocs/Modules/NaturalDocs/ConfigFile.pm
        deleted file mode 100644
        index e9fd7cc46..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/ConfigFile.pm
        +++ /dev/null
        @@ -1,508 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::ConfigFile
        -#
        -###############################################################################
        -#
        -#   A package to manage Natural Docs' configuration files.
        -#
        -#   Usage:
        -#
        -#       - Only one configuration file can be managed with this package at a time.  You must close the file before opening another
        -#         one.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::ConfigFile;
        -
        -
        -
        -#
        -#   Topic: Format
        -#
        -#   All configuration files are text files.
        -#
        -#   > # [comment]
        -#
        -#   Comments start with the # character.
        -#
        -#   > Format: [version]
        -#
        -#   All configuration files *must* have a format line as its first line containing content.  Whitespace and comments are permitted
        -#   ahead of it.
        -#
        -#   > [keyword]: [value]
        -#
        -#   Keywords can only contain <CFChars>.  Keywords are not case sensitive.  Values can be anything and run until the end of
        -#   the line or a comment.
        -#
        -#   > [value]
        -#
        -#   Lines that don't start with a valid keyword format are considered to be all value.
        -#
        -#   > [line] { [line] } [line]
        -#
        -#   Files supporting brace groups (specified in <Open()>) may also have braces that can appear anywhere.  It allows more than
        -#   one thing to appear per line, which isn't supported otherwise.  Consequently, values may not have braces.
        -#
        -
        -
        -#
        -#   Type: CFChars
        -#
        -#   The characters that can appear in configuration file keywords and user-defined element names: letters, numbers, spaces,
        -#   dashes, slashes, apostrophes, and periods.
        -#
        -#   Although the list above is exhaustive, it should be noted that you especially can *not* use colons (messes up keyword: value
        -#   sequences) commas (messes up item, item, item list sequences) and hashes (messes up comment detection.)
        -#
        -#   You can search the source code for [CFChars] to find all the instances where this definition is used.
        -#
        -
        -
        -###############################################################################
        -# Group: Variables
        -
        -#
        -#   handle: CONFIG_FILEHANDLE
        -#
        -#   The file handle used for the configuration file.
        -#
        -
        -
        -#
        -#   string: file
        -#
        -#   The <FileName> for the current configuration file being parsed.
        -#
        -my $file;
        -
        -
        -#
        -#	var: lineReader
        -#
        -#	The <LineReader> used to read the configuration file.
        -#
        -my $lineReader;
        -
        -
        -#
        -#   array: errors
        -#
        -#   An array of errors added by <AddError()>.  Every odd entry is the line number, and every even entry following is the
        -#   error message.
        -#
        -my @errors;
        -
        -
        -#
        -#   var: lineNumber
        -#
        -#   The current line number for the configuration file.
        -#
        -my $lineNumber;
        -
        -
        -#
        -#   bool: hasBraceGroups
        -#
        -#   Whether the file has brace groups or not.
        -#
        -my $hasBraceGroups;
        -
        -
        -#
        -#   array: virtualLines
        -#
        -#   An array of virtual lines if a line from the file contained more than one.
        -#
        -#   Files with brace groups may have more than one virtual line per actual file line, such as "Group: A { Group: B".  When that
        -#   happens, any extra virtual lines are put into here so they can be returned on the next call.
        -#
        -my @virtualLines;
        -
        -
        -
        -###############################################################################
        -# Group: Functions
        -
        -
        -#
        -#   Function: Open
        -#
        -#   Opens a configuration file for parsing and returns the format <VersionInt>.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName> to parse.
        -#       hasBraceGroups - Whether the file supports brace groups or not.  If so, lines with braces will be split apart behind the
        -#                                  scenes.
        -#
        -#   Returns:
        -#
        -#       The <VersionInt> of the file, or undef if the file doesn't exist.
        -#
        -sub Open #(file, hasBraceGroups)
        -    {
        -    my $self;
        -    ($self, $file, $hasBraceGroups) = @_;
        -
        -    @errors = ( );
        -
        -    # It will be incremented to one when the first line is read from the file.
        -    $lineNumber = 0;
        -
        -    open(CONFIG_FILEHANDLE, '<' . $file) or return undef;
        -    $lineReader = NaturalDocs::LineReader->New(\*CONFIG_FILEHANDLE);
        -
        -
        -    # Get the format line.
        -
        -    my ($keyword, $value, $comment) = $self->GetLine();
        -
        -    if ($keyword eq 'format')
        -        {  return NaturalDocs::Version->FromString($value);  }
        -    else
        -        {  die "The first content line in " . $file . " must be the Format: line.\n";  };
        -    };
        -
        -
        -#
        -#   Function: Close
        -#
        -#   Closes the current configuration file.
        -#
        -sub Close
        -    {
        -    my $self = shift;
        -    close(CONFIG_FILEHANDLE);
        -    };
        -
        -
        -#
        -#   Function: GetLine
        -#
        -#   Returns the next line containing content, or an empty array if none.
        -#
        -#   Returns:
        -#
        -#       Returns the array ( keyword, value, comment ), or an empty array if none.  All tabs will be converted to spaces, and all
        -#       whitespace will be condensed into a single space.
        -#
        -#       keyword - The keyword part of the line, if any.  Is converted to lowercase and doesn't include the colon.  If the file supports
        -#                       brace groups, opening and closing braces will be returned as keywords.
        -#       value - The value part of the line, minus any whitespace.  Keeps its original case.
        -#       comment - The comment following the line, if any.  This includes the # symbol and a leading space if there was
        -#                       any whitespace, since it may be significant.  Otherwise undef.  Used for lines where the # character needs to be
        -#                       accepted as part of the value.
        -#
        -sub GetLine
        -    {
        -    my $self = shift;
        -
        -    my ($line, $comment);
        -
        -
        -    # Get the next line with content.
        -
        -    do
        -        {
        -        # Get the next line.
        -
        -        my $isFileLine;
        -
        -        if (scalar @virtualLines)
        -            {
        -            $line = shift @virtualLines;
        -            $isFileLine = 0;
        -            }
        -        else
        -            {
        -            $line = $lineReader->Get();
        -            $lineNumber++;
        -
        -            if (!defined $line)
        -                {  return ( );  };
        -
        -            # Condense spaces and tabs into a single space.
        -            $line =~ tr/\t /  /s;
        -            $isFileLine = 1;
        -            };
        -
        -
        -        # Split off the comment.
        -
        -        if ($line =~ /^(.*?)( ?#.*)$/)
        -            {  ($line, $comment) = ($1, $2);  }
        -        else
        -            {  $comment = undef;  };
        -
        -
        -        # Split any brace groups.
        -
        -        if ($isFileLine && $hasBraceGroups && $line =~ /[\{\}]/)
        -            {
        -            ($line, @virtualLines) = split(/([\{\}])/, $line);
        -
        -            $virtualLines[-1] .= $comment;
        -            $comment = undef;
        -            };
        -
        -
        -        # Remove whitespace.
        -
        -        $line =~ s/^ //;
        -        $line =~ s/ $//;
        -        $comment =~ s/ $//;
        -        # We want to keep the leading space on a comment.
        -        }
        -    while (!$line);
        -
        -
        -    # Process the line.
        -
        -    if ($hasBraceGroups && ($line eq '{' || $line eq '}'))
        -        {
        -        return ($line, undef, undef);
        -        };
        -
        -
        -    if ($line =~ /^([a-z0-9\ \'\/\.\-]+?) ?: ?(.*)$/i) # [CFChars]
        -        {
        -        my ($keyword, $value) = ($1, $2);
        -        return (lc($keyword), $value, $comment);
        -        }
        -
        -    else
        -        {
        -        return (undef, $line, $comment);
        -        };
        -    };
        -
        -
        -#
        -#   Function: LineNumber
        -#
        -#   Returns the line number for the line last returned by <GetLine()>.
        -#
        -sub LineNumber
        -    {  return $lineNumber;  };
        -
        -
        -
        -###############################################################################
        -# Group: Error Functions
        -
        -
        -#
        -#   Function: AddError
        -#
        -#   Stores an error for the current configuration file.  Will be attached to the last line read by <GetLine()>.
        -#
        -#   Parameters:
        -#
        -#       message - The error message.
        -#       lineNumber - The line number to use.  If not specified, it will use the line number from the last call to <GetLine()>.
        -#
        -sub AddError #(message, lineNumber)
        -    {
        -    my ($self, $message, $messageLineNumber) = @_;
        -
        -    if (!defined $messageLineNumber)
        -        {  $messageLineNumber = $lineNumber;  };
        -
        -    push @errors, $messageLineNumber, $message;
        -    };
        -
        -
        -#
        -#   Function: ErrorCount
        -#
        -#   Returns how many errors the configuration file has.
        -#
        -sub ErrorCount
        -    {
        -    return (scalar @errors) / 2;
        -    };
        -
        -
        -#
        -#   Function: PrintErrorsAndAnnotateFile
        -#
        -#   Prints the errors to STDERR in the standard GNU format and annotates the configuration file with them.  It does *not* end
        -#   execution.  <Close()> *must* be called before this function.
        -#
        -sub PrintErrorsAndAnnotateFile
        -    {
        -    my ($self) = @_;
        -
        -    if (scalar @errors)
        -        {
        -        open(CONFIG_FILEHANDLE, '<' . $file);
        -
        -        my $lineReader = NaturalDocs::LineReader->New(\*CONFIG_FILEHANDLE);
        -        my @lines = $lineReader->GetAll();
        -
        -        close(CONFIG_FILEHANDLE);
        -
        -        # We need to keep track of both the real and the original line numbers.  The original line numbers are for matching errors in
        -        # the errors array, and don't include any comment lines added or deleted.  Line number is the current line number including
        -        # those comment lines for sending to the display.
        -        my $lineNumber = 1;
        -        my $originalLineNumber = 1;
        -
        -        open(CONFIG_FILEHANDLE, '>' . $file);
        -
        -        # We don't want to keep the old error header, if present.
        -        if ($lines[0] =~ /^\# There (?:is an error|are \d+ errors) in this file\./)
        -            {
        -            shift @lines;
        -            $originalLineNumber++;
        -
        -            # We want to drop the blank line after it as well.
        -            if ($lines[0] eq "\n")
        -                {
        -                shift @lines;
        -                $originalLineNumber++;
        -                };
        -            };
        -
        -        if ($self->ErrorCount() == 1)
        -            {
        -            print CONFIG_FILEHANDLE
        -            "# There is an error in this file.  Search for ERROR to find it.\n\n";
        -            }
        -        else
        -            {
        -            print CONFIG_FILEHANDLE
        -            "# There are " . $self->ErrorCount() . " errors in this file.  Search for ERROR to find them.\n\n";
        -            };
        -
        -        $lineNumber += 2;
        -
        -
        -        foreach my $line (@lines)
        -            {
        -            while (scalar @errors && $originalLineNumber == $errors[0])
        -                {
        -                my $errorLine = shift @errors;
        -                my $errorMessage = shift @errors;
        -
        -                print CONFIG_FILEHANDLE "# ERROR: " . $errorMessage . "\n";
        -
        -                # Use the GNU error format, which should make it easier to handle errors when Natural Docs is part of a build process.
        -                # See http://www.gnu.org/prep/standards_15.html
        -
        -                $errorMessage = lcfirst($errorMessage);
        -                $errorMessage =~ s/\.$//;
        -
        -                print STDERR 'NaturalDocs:' . $file . ':' . $lineNumber . ': ' . $errorMessage . "\n";
        -
        -                $lineNumber++;
        -                };
        -
        -            # We want to remove error lines from previous runs.
        -            if (substr($line, 0, 9) ne '# ERROR: ')
        -                {
        -                print CONFIG_FILEHANDLE $line;
        -                $lineNumber++;
        -                };
        -
        -            $originalLineNumber++;
        -            };
        -
        -        # Clean up any remaining errors.
        -        while (scalar @errors)
        -            {
        -            my $errorLine = shift @errors;
        -            my $errorMessage = shift @errors;
        -
        -            print CONFIG_FILEHANDLE "# ERROR: " . $errorMessage . "\n";
        -
        -            # Use the GNU error format, which should make it easier to handle errors when Natural Docs is part of a build process.
        -            # See http://www.gnu.org/prep/standards_15.html
        -
        -            $errorMessage = lcfirst($errorMessage);
        -            $errorMessage =~ s/\.$//;
        -
        -            print STDERR 'NaturalDocs:' . $file . ':' . $lineNumber . ': ' . $errorMessage . "\n";
        -            };
        -
        -        close(CONFIG_FILEHANDLE);
        -        };
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Misc Functions
        -
        -
        -#
        -#   Function: HasOnlyCFChars
        -#
        -#   Returns whether the passed string contains only <CFChars>.
        -#
        -sub HasOnlyCFChars #(string)
        -    {
        -    my ($self, $string) = @_;
        -    return ($string =~ /^[a-z0-9\ \.\-\/\']*$/i);  # [CFChars]
        -    };
        -
        -
        -#
        -#   Function: CFCharNames
        -#
        -#   Returns a plain-english list of <CFChars> which can be embedded in a sentence.  For example, "You can only use
        -#   [CFCharsList()] in the name.
        -#
        -sub CFCharNames
        -    {
        -    # [CFChars]
        -    return 'letters, numbers, spaces, periods, dashes, slashes, and apostrophes';
        -    };
        -
        -
        -#
        -#   Function: Obscure
        -#
        -#   Obscures the passed text so that it is not user editable and returns it.  The encoding method is not secure; it is just designed
        -#   to be fast and to discourage user editing.
        -#
        -sub Obscure #(text)
        -    {
        -    my ($self, $text) = @_;
        -
        -    # ` is specifically chosen to encode to space because of its rarity.  We don't want a trailing one to get cut off before decoding.
        -    $text =~ tr{a-zA-Z0-9\ \\\/\.\:\_\-\`}
        -                    {pY9fGc\`R8lAoE\\uIdH6tN\/7sQjKx0B5mW\.vZ41PyFg\:CrLaO\_eUi2DhT\-nSqJkXb3MwVz\ };
        -
        -    return $text;
        -    };
        -
        -
        -#
        -#   Function: Unobscure
        -#
        -#   Restores text encoded with <Obscure()> and returns it.
        -#
        -sub Unobscure #(text)
        -    {
        -    my ($self, $text) = @_;
        -
        -    $text =~ tr{pY9fGc\`R8lAoE\\uIdH6tN\/7sQjKx0B5mW\.vZ41PyFg\:CrLaO\_eUi2DhT\-nSqJkXb3MwVz\ }
        -                    {a-zA-Z0-9\ \\\/\.\:\_\-\`};
        -
        -    return $text;
        -    };
        -
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Constants.pm b/vendor/naturaldocs/Modules/NaturalDocs/Constants.pm
        deleted file mode 100644
        index 66d934c29..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Constants.pm
        +++ /dev/null
        @@ -1,166 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Constants
        -#
        -###############################################################################
        -#
        -#   Constants that are used throughout the script.  All are exported by default.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Constants;
        -
        -use vars qw(@EXPORT @ISA);
        -require Exporter;
        -@ISA = qw(Exporter);
        -
        -@EXPORT = ('MENU_TITLE', 'MENU_SUBTITLE', 'MENU_FILE', 'MENU_GROUP', 'MENU_TEXT', 'MENU_LINK', 'MENU_FOOTER',
        -                   'MENU_INDEX', 'MENU_FORMAT', 'MENU_ENDOFORIGINAL', 'MENU_DATA',
        -
        -                   'MENU_FILE_NOAUTOTITLE', 'MENU_GROUP_UPDATETITLES', 'MENU_GROUP_UPDATESTRUCTURE',
        -                   'MENU_GROUP_UPDATEORDER', 'MENU_GROUP_HASENDOFORIGINAL',
        -                   'MENU_GROUP_UNSORTED', 'MENU_GROUP_FILESSORTED',
        -                   'MENU_GROUP_FILESANDGROUPSSORTED', 'MENU_GROUP_EVERYTHINGSORTED',
        -                   'MENU_GROUP_ISINDEXGROUP',
        -
        -                   'FILE_NEW', 'FILE_CHANGED', 'FILE_SAME', 'FILE_DOESNTEXIST');
        -
        -#
        -#   Topic: Assumptions
        -#
        -#   - No constant here will ever be zero.
        -#   - All constants are exported by default.
        -#
        -
        -
        -###############################################################################
        -# Group: Virtual Types
        -# These are only groups of constants, but should be treated like typedefs or enums.  Each one represents a distinct type and
        -# their values should only be one of their constants or undef.
        -
        -
        -#
        -#   Constants: MenuEntryType
        -#
        -#   The types of entries that can appear in the menu.
        -#
        -#       MENU_TITLE         - The title of the menu.
        -#       MENU_SUBTITLE   - The sub-title of the menu.
        -#       MENU_FILE           - A source file, relative to the source directory.
        -#       MENU_GROUP       - A group.
        -#       MENU_TEXT          - Arbitrary text.
        -#       MENU_LINK           - A web link.
        -#       MENU_FOOTER      - Footer text.
        -#       MENU_INDEX        - An index.
        -#       MENU_FORMAT     - The version of Natural Docs the menu file was generated with.
        -#       MENU_ENDOFORIGINAL - A dummy entry that marks where the original group content ends.  This is used when automatically
        -#                                           changing the groups so that the alphabetization or lack thereof can be detected without being
        -#                                           affected by new entries tacked on to the end.
        -#       MENU_DATA - Data not meant for user editing.
        -#
        -#   Dependency:
        -#
        -#       <PreviousMenuState.nd> depends on these values all being able to fit into a UInt8, i.e. <= 255.
        -#
        -use constant MENU_TITLE => 1;
        -use constant MENU_SUBTITLE => 2;
        -use constant MENU_FILE => 3;
        -use constant MENU_GROUP => 4;
        -use constant MENU_TEXT => 5;
        -use constant MENU_LINK => 6;
        -use constant MENU_FOOTER => 7;
        -use constant MENU_INDEX => 8;
        -use constant MENU_FORMAT => 9;
        -use constant MENU_ENDOFORIGINAL => 10;
        -use constant MENU_DATA => 11;
        -
        -
        -#
        -#   Constants: FileStatus
        -#
        -#   What happened to a file since Natural Docs' last execution.
        -#
        -#       FILE_NEW                - The file has been added since the last run.
        -#       FILE_CHANGED        - The file has been modified since the last run.
        -#       FILE_SAME               - The file hasn't been modified since the last run.
        -#       FILE_DOESNTEXIST  - The file doesn't exist, or was deleted.
        -#
        -use constant FILE_NEW => 1;
        -use constant FILE_CHANGED => 2;
        -use constant FILE_SAME => 3;
        -use constant FILE_DOESNTEXIST => 4;
        -
        -
        -
        -###############################################################################
        -# Group: Flags
        -# These constants can be combined with each other.
        -
        -
        -#
        -#   Constants: Menu Entry Flags
        -#
        -#   The various flags that can apply to a menu entry.  You cannot mix flags of different types, since they may overlap.
        -#
        -#   File Flags:
        -#
        -#       MENU_FILE_NOAUTOTITLE - Whether the file is auto-titled or not.
        -#
        -#   Group Flags:
        -#
        -#       MENU_GROUP_UPDATETITLES - The group should have its auto-titles regenerated.
        -#       MENU_GROUP_UPDATESTRUCTURE - The group should be checked for structural changes, such as being removed or being
        -#                                                             split into subgroups.
        -#       MENU_GROUP_UPDATEORDER - The group should be resorted.
        -#
        -#       MENU_GROUP_HASENDOFORIGINAL - Whether the group contains a dummy <MENU_ENDOFORIGINAL> entry.
        -#       MENU_GROUP_ISINDEXGROUP - Whether the group is used primarily for <MENU_INDEX> entries.  <MENU_TEXT> entries
        -#                                                       are tolerated.
        -#
        -#       MENU_GROUP_UNSORTED - The group's contents are not sorted.
        -#       MENU_GROUP_FILESSORTED - The group's files are sorted alphabetically.
        -#       MENU_GROUP_FILESANDGROUPSSORTED - The group's files and sub-groups are sorted alphabetically.
        -#       MENU_GROUP_EVERYTHINGSORTED - All entries in the group are sorted alphabetically.
        -#
        -use constant MENU_FILE_NOAUTOTITLE => 0x0001;
        -
        -use constant MENU_GROUP_UPDATETITLES => 0x0001;
        -use constant MENU_GROUP_UPDATESTRUCTURE => 0x0002;
        -use constant MENU_GROUP_UPDATEORDER => 0x0004;
        -use constant MENU_GROUP_HASENDOFORIGINAL => 0x0008;
        -
        -# This could really be a two-bit field instead of four flags, but it's not worth the effort since it's only used internally.
        -use constant MENU_GROUP_UNSORTED => 0x0010;
        -use constant MENU_GROUP_FILESSORTED => 0x0020;
        -use constant MENU_GROUP_FILESANDGROUPSSORTED => 0x0040;
        -use constant MENU_GROUP_EVERYTHINGSORTED => 0x0080;
        -
        -use constant MENU_GROUP_ISINDEXGROUP => 0x0100;
        -
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -
        -#
        -#   Function: IsClassHierarchyReference
        -#   Returns whether the passed <ReferenceType> belongs to <NaturalDocs::ClassHierarchy>.
        -#
        -sub IsClassHierarchyReference #(reference)
        -    {
        -    my ($self, $reference) = @_;
        -    return ($reference == ::REFERENCE_CH_CLASS() || $reference == ::REFERENCE_CH_PARENT());
        -    };
        -
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/DefineMembers.pm b/vendor/naturaldocs/Modules/NaturalDocs/DefineMembers.pm
        deleted file mode 100644
        index 8e04d3ddd..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/DefineMembers.pm
        +++ /dev/null
        @@ -1,101 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::DefineMembers
        -#
        -###############################################################################
        -#
        -#   A custom Perl pragma to define member constants and accessors for use in Natural Docs objects while supporting inheritance.
        -#
        -#   Each member will be defined as a numeric constant which should be used as that variable's index into the object arrayref.
        -#   They will be assigned sequentially from zero, and take into account any members defined this way in parent classes.  Note
        -#   that you can *not* use multiple inheritance with this method.
        -#
        -#   If a parameter ends in parenthesis, it will be generated as an accessor for the previous member.  If it also starts with "Set",
        -#   the accessor will accept a single parameter to replace the value with.  If it's followed with "duparrayref", it will assume the
        -#   parameter is either an arrayref or undef, and if the former, will duplicate it to set the value.
        -#
        -#   Example:
        -#
        -#   > package MyPackage;
        -#   >
        -#   > use NaturalDocs::DefineMembers 'VAR_A', 'VarA()', 'SetVarA()',
        -#   >                                'VAR_B', 'VarB()',
        -#   >                                'VAR_C',
        -#   >                                'VAR_D', 'VarD()', 'SetVarD() duparrayref';
        -#   >
        -#   > sub SetC #(C)
        -#   >    {
        -#   >    my ($self, $c) = @_;
        -#   >    $self->[VAR_C] = $c;
        -#   >    };
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -
        -package NaturalDocs::DefineMembers;
        -
        -sub import #(member, member, ...)
        -    {
        -    my ($self, @parameters) = @_;
        -    my $package = caller();
        -
        -    no strict 'refs';
        -    my $parent = ${$package . '::ISA'}[0];
        -    use strict 'refs';
        -
        -    my $memberConstant = 0;
        -    my $lastMemberName;
        -
        -    if (defined $parent && $parent->can('END_OF_MEMBERS'))
        -        {  $memberConstant = $parent->END_OF_MEMBERS();  };
        -
        -    my $code = '{ package ' . $package . ";\n";
        -
        -    foreach my $parameter (@parameters)
        -        {
        -        if ($parameter =~ /^(.+)\(\) *(duparrayref)?$/i)
        -            {
        -            my ($functionName, $pragma) = ($1, lc($2));
        -
        -            if ($functionName =~ /^Set/)
        -                {
        -                if ($pragma eq 'duparrayref')
        -                    {
        -                    $code .=
        -                    'sub ' . $functionName . '
        -                        {
        -                        if (defined $_[1])
        -                            {  $_[0]->[' . $lastMemberName . '] = [ @{$_[1]} ];  }
        -                        else
        -                            {  $_[0]->[' . $lastMemberName . '] = undef;  };
        -                        };' . "\n";
        -                    }
        -                else
        -                    {
        -                    $code .= 'sub ' . $functionName . ' { $_[0]->[' . $lastMemberName . '] = $_[1];  };' . "\n";
        -                    };
        -                }
        -            else
        -                {
        -                $code .= 'sub ' . $functionName . ' { return $_[0]->[' . $lastMemberName . '];  };' . "\n";
        -                };
        -            }
        -        else
        -            {
        -            $code .= 'use constant ' . $parameter . ' => ' . $memberConstant . ";\n";
        -            $memberConstant++;
        -            $lastMemberName = $parameter;
        -            };
        -        };
        -
        -    $code .= 'use constant END_OF_MEMBERS => ' . $memberConstant . ";\n";
        -    $code .= '};';
        -
        -    eval $code;
        -    };
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Error.pm b/vendor/naturaldocs/Modules/NaturalDocs/Error.pm
        deleted file mode 100644
        index 5b300607b..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Error.pm
        +++ /dev/null
        @@ -1,306 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Error
        -#
        -###############################################################################
        -#
        -#   Manages all aspects of error handling in Natural Docs.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -$SIG{'__DIE__'} = \&NaturalDocs::Error::CatchDeath;
        -
        -
        -package NaturalDocs::Error;
        -
        -
        -###############################################################################
        -# Group: Variables
        -
        -
        -#
        -#   handle: FH_CRASHREPORT
        -#   The filehandle used for generating crash reports.
        -#
        -
        -
        -#
        -#   var: stackTrace
        -#   The stack trace generated by <CatchDeath()>.
        -#
        -my $stackTrace;
        -
        -
        -#
        -#   var: softDeath
        -#   Whether the program exited using <SoftDeath()>.
        -#
        -my $softDeath;
        -
        -
        -#
        -#   var: currentAction
        -#   What Natural Docs was doing when it crashed.  This stores strings generated by functions like <OnStartParsing()>.
        -#
        -my $currentAction;
        -
        -
        -###############################################################################
        -# Group: Functions
        -
        -
        -#
        -#   Function: SoftDeath
        -#
        -#   Generates a "soft" death, which means the program exits like with Perl's die(), but no crash report will be generated.
        -#
        -#   Parameter:
        -#
        -#       message - The error message to die with.
        -#
        -sub SoftDeath #(message)
        -    {
        -    my ($self, $message) = @_;
        -
        -    $softDeath = 1;
        -    if ($message !~ /\n$/)
        -        {  $message .= "\n";  };
        -
        -    die $message;
        -    };
        -
        -
        -#
        -#   Function: OnStartParsing
        -#
        -#   Called whenever <NaturalDocs::Parser> starts parsing a source file.
        -#
        -sub OnStartParsing #(FileName file)
        -    {
        -    my ($self, $file) = @_;
        -    $currentAction = 'Parsing ' . $file;
        -    };
        -
        -
        -#
        -#   Function: OnEndParsing
        -#
        -#   Called whenever <NaturalDocs::Parser> is done parsing a source file.
        -#
        -sub OnEndParsing #(FileName file)
        -    {
        -    my ($self, $file) = @_;
        -    $currentAction = undef;
        -    };
        -
        -
        -#
        -#   Function: OnStartBuilding
        -#
        -#   Called whenever <NaturalDocs::Builder> starts building a source file.
        -#
        -sub OnStartBuilding #(FileName file)
        -    {
        -    my ($self, $file) = @_;
        -    $currentAction = 'Building ' . $file;
        -    };
        -
        -
        -#
        -#   Function: OnEndBuilding
        -#
        -#   Called whenever <NaturalDocs::Builder> is done building a source file.
        -#
        -sub OnEndBuilding #(FileName file)
        -    {
        -    my ($self, $file) = @_;
        -    $currentAction = undef;
        -    };
        -
        -
        -#
        -#   Function: HandleDeath
        -#
        -#   Should be called whenever Natural Docs dies out of execution.
        -#
        -sub HandleDeath
        -    {
        -    my $self = shift;
        -
        -    my $reason = $::EVAL_ERROR;
        -    $reason =~ s/[\n\r]+$//;
        -
        -    my $errorMessage =
        -         "\n"
        -         . "Natural Docs encountered the following error and was stopped:\n"
        -         . "\n"
        -         . "   " . $reason . "\n"
        -         . "\n"
        -
        -         . "You can get help at the following web site:\n"
        -         . "\n"
        -         . "   " . NaturalDocs::Settings->AppURL() . "\n"
        -         . "\n";
        -
        -    if (!$softDeath)
        -        {
        -        my $crashReport = $self->GenerateCrashReport();
        -
        -        if ($crashReport)
        -            {
        -            $errorMessage .=
        -             "If sending an error report, please include the information found in the\n"
        -             . "following file:\n"
        -             . "\n"
        -             . "   " . $crashReport . "\n"
        -             . "\n";
        -            }
        -        else
        -            {
        -            $errorMessage .=
        -             "If sending an error report, please include the following information:\n"
        -             . "\n"
        -             . "   Natural Docs version: " . NaturalDocs::Settings->TextAppVersion() . "\n"
        -             . "   Perl version: " . $self->PerlVersion() . " on " . $::OSNAME . "\n"
        -             . "\n";
        -             };
        -        };
        -
        -    die $errorMessage;
        -    };
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -
        -#
        -#   Function: PerlVersion
        -#   Returns the current Perl version as a string.
        -#
        -sub PerlVersion
        -    {
        -    my $self = shift;
        -
        -    my $perlVersion;
        -
        -    if ($^V)
        -        {  $perlVersion = sprintf('%vd', $^V);  }
        -    if (!$perlVersion || substr($perlVersion, 0, 1) eq '%')
        -        {  $perlVersion = $];  };
        -
        -    return $perlVersion;
        -    };
        -
        -
        -#
        -#   Function: GenerateCrashReport
        -#
        -#   Generates a report and returns the <FileName> it's located at.  Returns undef if it could not generate one.
        -#
        -sub GenerateCrashReport
        -    {
        -    my $self = shift;
        -
        -    my $errorMessage = $::EVAL_ERROR;
        -    $errorMessage =~ s/[\r\n]+$//;
        -
        -    my $reportDirectory = NaturalDocs::Settings->ProjectDirectory();
        -
        -    if (!$reportDirectory || !-d $reportDirectory)
        -        {  return undef;  };
        -
        -    my $file = NaturalDocs::File->JoinPaths($reportDirectory, 'LastCrash.txt');
        -
        -    open(FH_CRASHREPORT, '>' . $file) or return undef;
        -
        -    print FH_CRASHREPORT
        -    'Crash Message:' . "\n\n"
        -    . '   ' . $errorMessage . "\n\n";
        -
        -    if ($currentAction)
        -        {
        -        print FH_CRASHREPORT
        -        'Current Action:' . "\n\n"
        -        . '   ' . $currentAction . "\n\n";
        -        };
        -
        -    print FH_CRASHREPORT
        -    'Natural Docs version ' . NaturalDocs::Settings->TextAppVersion() . "\n"
        -    . 'Perl version ' . $self->PerlVersion . ' on ' . $::OSNAME . "\n\n"
        -    . 'Command Line:' . "\n\n"
        -    . '   ' . join(' ', @ARGV) . "\n\n";
        -
        -    if ($stackTrace)
        -        {
        -        print FH_CRASHREPORT
        -        'Stack Trace:' . "\n\n"
        -        . $stackTrace;
        -        }
        -    else
        -        {
        -        print FH_CRASHREPORT
        -        'Stack Trace not available.' . "\n\n";
        -        };
        -
        -    close(FH_CRASHREPORT);
        -    return $file;
        -    };
        -
        -
        -###############################################################################
        -# Group: Signal Handlers
        -
        -
        -#
        -#   Function: CatchDeath
        -#
        -#   Catches Perl die calls.
        -#
        -#   *IMPORTANT:* This function is a signal handler and should not be called manually.  Also, because of this, it does not have
        -#   a $self parameter.
        -#
        -#   Parameters:
        -#
        -#       message - The error message to die with.
        -#
        -sub CatchDeath #(message)
        -    {
        -    # No $self because it's a signal handler.
        -    my $message = shift;
        -
        -    if (!$NaturalDocs::Error::softDeath)
        -        {
        -        my $i = 0;
        -        my ($lastPackage, $lastFile, $lastLine, $lastFunction);
        -
        -        while (my ($package, $file, $line, $function) = caller($i))
        -            {
        -            if ($i != 0)
        -                {  $stackTrace .= ', called from' . "\n";  };
        -
        -            $stackTrace .= '   ' . $function;
        -
        -            if (defined $lastLine)
        -                {
        -                $stackTrace .= ', line ' . $lastLine;
        -
        -                if ($function !~ /^NaturalDocs::/)
        -                    {  $stackTrace .= ' of ' . $lastFile;  };
        -                };
        -
        -            ($lastPackage, $lastFile, $lastLine, $lastFunction) = ($package, $file, $line, $function);
        -            $i++;
        -            };
        -        };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/File.pm b/vendor/naturaldocs/Modules/NaturalDocs/File.pm
        deleted file mode 100644
        index 9a13c99a2..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/File.pm
        +++ /dev/null
        @@ -1,541 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::File
        -#
        -###############################################################################
        -#
        -#   A package to manage file access across platforms.  Incorporates functions from various standard File:: packages, but more
        -#   importantly, works around the glorious suckage present in File::Spec, at least in version 0.82 and earlier.  Read the "Why oh
        -#   why?" sections for why this package was necessary.
        -#
        -#   Usage and Dependencies:
        -#
        -#       - The package doesn't depend on any other Natural Docs packages and is ready to use immediately.
        -#
        -#       - All functions except <CanonizePath()> assume that all parameters are canonized.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use File::Spec ();
        -use File::Path ();
        -use File::Copy ();
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::File;
        -
        -
        -#
        -#   Function: CheckCompatibility
        -#
        -#   Checks if the standard packages required by this one are up to snuff and dies if they aren't.  This is done because I can't
        -#   tell which versions of File::Spec have splitpath just by the version numbers.
        -#
        -sub CheckCompatibility
        -    {
        -    my ($self) = @_;
        -
        -    eval {
        -        File::Spec->splitpath('');
        -    };
        -
        -    if ($@)
        -        {
        -        NaturalDocs::Error->SoftDeath("Natural Docs requires a newer version of File::Spec than you have.  "
        -                                                    . "You must either upgrade it or upgrade Perl.");
        -        };
        -    };
        -
        -
        -###############################################################################
        -# Group: Path String Functions
        -
        -
        -#
        -#   Function: CanonizePath
        -#
        -#   Takes a path and returns a logically simplified version of it.
        -#
        -#   Why oh why?:
        -#
        -#       Because File::Spec->canonpath doesn't strip quotes on Windows.  So if you pass in "a b\c" or "a b"\c, they still end up as
        -#       different strings even though they're logically the same.
        -#
        -#       It also doesn't remove things like "..", so "a/b/../c" doesn't simplify to "a/c" like it should.
        -#
        -sub CanonizePath #(path)
        -    {
        -    my ($self, $path) = @_;
        -
        -    if ($::OSNAME eq 'MSWin32')
        -        {
        -        # We don't have to use a smarter algorithm for dropping quotes because they're invalid characters for actual file and
        -        # directory names.
        -        $path =~ s/\"//g;
        -        };
        -
        -    $path = File::Spec->canonpath($path);
        -
        -    # Condense a/b/../c into a/c.
        -
        -    my $upDir = File::Spec->updir();
        -    if (index($path, $upDir) != -1)
        -        {
        -        my ($volume, $directoryString, $file) = $self->SplitPath($path);
        -        my @directories = $self->SplitDirectories($directoryString);
        -
        -        my $i = 1;
        -        while ($i < scalar @directories)
        -            {
        -            if ($i > 0 && $directories[$i] eq $upDir && $directories[$i - 1] ne $upDir)
        -                {
        -                splice(@directories, $i - 1, 2);
        -                $i--;
        -                }
        -            else
        -                {  $i++;  };
        -            };
        -
        -        $directoryString = $self->JoinDirectories(@directories);
        -        $path = $self->JoinPath($volume, $directoryString, $file);
        -        };
        -
        -    return $path;
        -    };
        -
        -
        -#
        -#   Function: PathIsAbsolute
        -#
        -#   Returns whether the passed path is absolute.
        -#
        -sub PathIsAbsolute #(path)
        -    {
        -    my ($self, $path) = @_;
        -    return File::Spec->file_name_is_absolute($path);
        -    };
        -
        -
        -#
        -#   Function: JoinPath
        -#
        -#   Creates a path from its elements.
        -#
        -#   Parameters:
        -#
        -#       volume - The volume, such as the drive letter on Windows.  Undef if none.
        -#       dirString - The directory string.  Create with <JoinDirectories()> if necessary.
        -#       file - The file name, or undef if none.
        -#
        -#   Returns:
        -#
        -#       The joined path.
        -#
        -sub JoinPath #(volume, dirString, $file)
        -    {
        -    my ($self, $volume, $dirString, $file) = @_;
        -    return File::Spec->catpath($volume, $dirString, $file);
        -    };
        -
        -
        -#
        -#   Function: JoinPaths
        -#
        -#   Joins two paths.
        -#
        -#   Parameters:
        -#
        -#       basePath       - May be a relative path, an absolute path, or undef.
        -#       extraPath      - May be a relative path, a file, a relative path and file together, or undef.
        -#       noFileInExtra - Set this to true if extraPath is a relative path only, and doesn't have a file.
        -#
        -#   Returns:
        -#
        -#       The joined path.
        -#
        -#   Why oh why?:
        -#
        -#       Because nothing in File::Spec will simply slap two paths together.  They have to be split up for catpath/file, and rel2abs
        -#       requires the base to be absolute.
        -#
        -sub JoinPaths #(basePath, extraPath, noFileInExtra)
        -    {
        -    my ($self, $basePath, $extraPath, $noFileInExtra) = @_;
        -
        -    # If both are undef, it will return undef, which is what we want.
        -    if (!defined $basePath)
        -        {  return $extraPath;  }
        -    elsif (!defined $extraPath)
        -        {  return $basePath;  };
        -
        -    my ($baseVolume, $baseDirString, $baseFile) = File::Spec->splitpath($basePath, 1);
        -    my ($extraVolume, $extraDirString, $extraFile) = File::Spec->splitpath($extraPath, $noFileInExtra);
        -
        -    my @baseDirectories = $self->SplitDirectories($baseDirString);
        -    my @extraDirectories = $self->SplitDirectories($extraDirString);
        -
        -    my $fullDirString = $self->JoinDirectories(@baseDirectories, @extraDirectories);
        -
        -    my $fullPath = File::Spec->catpath($baseVolume, $fullDirString, $extraFile);
        -
        -    return $self->CanonizePath($fullPath);
        -    };
        -
        -
        -#
        -#   Function: SplitPath
        -#
        -#   Takes a path and returns its elements.
        -#
        -#   Parameters:
        -#
        -#       path - The path to split.
        -#       noFile - Set to true if the path doesn't have a file at the end.
        -#
        -#   Returns:
        -#
        -#       The array ( volume, directoryString, file ).  If any don't apply, they will be undef.  Use <SplitDirectories()> to split the
        -#       directory string if desired.
        -#
        -#   Why oh Why?:
        -#
        -#       Because File::Spec->splitpath may leave a trailing slash/backslash/whatever on the directory string, which makes
        -#       it a bit hard to match it with results from File::Spec->catdir.
        -#
        -sub SplitPath #(path, noFile)
        -    {
        -    my ($self, $path, $noFile) = @_;
        -
        -    my @segments = File::Spec->splitpath($path, $noFile);
        -
        -    if (!length $segments[0])
        -        {  $segments[0] = undef;  };
        -    if (!length $segments[2])
        -        {  $segments[2] = undef;  };
        -
        -    $segments[1] = File::Spec->catdir( File::Spec->splitdir($segments[1]) );
        -
        -    return @segments;
        -    };
        -
        -
        -#
        -#   Function: JoinDirectories
        -#
        -#   Creates a directory string from an array of directory names.
        -#
        -#   Parameters:
        -#
        -#       directory - A directory name.  There may be as many of these as desired.
        -#
        -sub JoinDirectories #(directory, directory, ...)
        -    {
        -    my ($self, @directories) = @_;
        -    return File::Spec->catdir(@directories);
        -    };
        -
        -
        -#
        -#   Function: SplitDirectories
        -#
        -#   Takes a string of directories and returns an array of its elements.
        -#
        -#   Why oh why?:
        -#
        -#       Because File::Spec->splitdir might leave an empty element at the end of the array, which screws up both joining in
        -#       <ConvertToURL> and navigation in <MakeRelativePath>.
        -#
        -sub SplitDirectories #(directoryString)
        -    {
        -    my ($self, $directoryString) = @_;
        -
        -    my @directories = File::Spec->splitdir($directoryString);
        -
        -    if (!length $directories[-1])
        -        {  pop @directories;  };
        -
        -    return @directories;
        -    };
        -
        -
        -#
        -#   Function: MakeRelativePath
        -#
        -#   Takes two paths and returns a relative path between them.
        -#
        -#   Parameters:
        -#
        -#       basePath    - The starting path.  May be relative or absolute, so long as the target path is as well.
        -#       targetPath  - The target path.  May be relative or absolute, so long as the base path is as well.
        -#
        -#       If both paths are relative, they are assumed to be relative to the same base.
        -#
        -#   Returns:
        -#
        -#       The target path relative to base.
        -#
        -#   Why oh why?:
        -#
        -#       First, there's nothing that gives a relative path between two relative paths.
        -#
        -#       Second, if target and base are absolute but on different volumes, File::Spec->abs2rel creates a totally non-functional
        -#       relative path.  It should return the target as is, since there is no relative path.
        -#
        -#       Third, File::Spec->abs2rel between absolute paths on the same volume, at least on Windows, leaves the drive letter
        -#       on.  So abs2rel('a:\b\c\d', 'a:\b') returns 'a:c\d' instead of the expected 'c\d'.  That makes no sense whatsoever.  It's
        -#       not like it was designed to handle only directory names, either; the documentation says 'path' and the code seems to
        -#       explicitly handle it.  There's just an 'unless' in there that tacks on the volume, defeating the purpose of a *relative* path
        -#       and making the function worthless.
        -#
        -sub MakeRelativePath #(basePath, targetPath)
        -    {
        -    my ($self, $basePath, $targetPath) = @_;
        -
        -    my ($baseVolume, $baseDirString, $baseFile) = $self->SplitPath($basePath, 1);
        -    my ($targetVolume, $targetDirString, $targetFile) = $self->SplitPath($targetPath);
        -
        -    # If the volumes are different, there is no possible relative path.
        -    if ($targetVolume ne $baseVolume)
        -        {  return $targetPath;  };
        -
        -    my @baseDirectories = $self->SplitDirectories($baseDirString);
        -    my @targetDirectories = $self->SplitDirectories($targetDirString);
        -
        -    # Skip the parts of the path that are the same.
        -    while (scalar @baseDirectories && @targetDirectories && $baseDirectories[0] eq $targetDirectories[0])
        -        {
        -        shift @baseDirectories;
        -        shift @targetDirectories;
        -        };
        -
        -    # Back out of the base path until it reaches where they were similar.
        -    for (my $i = 0; $i < scalar @baseDirectories; $i++)
        -        {
        -        unshift @targetDirectories, File::Spec->updir();
        -        };
        -
        -    $targetDirString = $self->JoinDirectories(@targetDirectories);
        -
        -    return File::Spec->catpath(undef, $targetDirString, $targetFile);
        -    };
        -
        -
        -#
        -#   Function: IsSubPathOf
        -#
        -#   Returns whether the path is a descendant of another path.
        -#
        -#   Parameters:
        -#
        -#       base - The base path to test against.
        -#       path - The possible subpath to test.
        -#
        -#   Returns:
        -#
        -#       Whether path is a descendant of base.
        -#
        -sub IsSubPathOf #(base, path)
        -    {
        -    my ($self, $base, $path) = @_;
        -
        -    # This is a quick test that should find a false quickly.
        -    if ($base eq substr($path, 0, length($base)))
        -        {
        -        # This doesn't guarantee true, because it could be "C:\A B" and "C:\A B C\File".  So we test for it by seeing if the last
        -        # directory in base is the same as the equivalent directory in path.
        -
        -        my ($baseVolume, $baseDirString, $baseFile) = NaturalDocs::File->SplitPath($base, 1);
        -        my @baseDirectories = NaturalDocs::File->SplitDirectories($baseDirString);
        -
        -        my ($pathVolume, $pathDirString, $pathFile) = NaturalDocs::File->SplitPath($path);
        -        my @pathDirectories = NaturalDocs::File->SplitDirectories($pathDirString);
        -
        -        return ( $baseDirectories[-1] eq $pathDirectories[ scalar @baseDirectories - 1 ] );
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: ConvertToURL
        -#
        -#   Takes a relative path and converts it from the native format to a relative URL.  Note that it _doesn't_ convert special characters
        -#   to amp chars.
        -#
        -sub ConvertToURL #(path)
        -    {
        -    my ($self, $path) = @_;
        -
        -    my ($pathVolume, $pathDirString, $pathFile) = $self->SplitPath($path);
        -    my @pathDirectories = $self->SplitDirectories($pathDirString);
        -
        -    my $i = 0;
        -    while ($i < scalar @pathDirectories && $pathDirectories[$i] eq File::Spec->updir())
        -        {
        -        $pathDirectories[$i] = '..';
        -        $i++;
        -        };
        -
        -    return join('/', @pathDirectories, $pathFile);
        -    };
        -
        -
        -#
        -#   Function: NoUpwards
        -#
        -#   Takes an array of directory entries and returns one without all the entries that refer to the parent directory, such as '.' and '..'.
        -#
        -sub NoUpwards #(array)
        -    {
        -    my ($self, @array) = @_;
        -    return File::Spec->no_upwards(@array);
        -    };
        -
        -
        -#
        -#   Function: NoFileName
        -#
        -#   Takes a path and returns a version without the file name.  Useful for sending paths to <CreatePath()>.
        -#
        -sub NoFileName #(path)
        -    {
        -    my ($self, $path) = @_;
        -
        -    my ($pathVolume, $pathDirString, $pathFile) = File::Spec->splitpath($path);
        -
        -    return File::Spec->catpath($pathVolume, $pathDirString, undef);
        -    };
        -
        -
        -#
        -#   Function: NoExtension
        -#
        -#   Returns the path without an extension.
        -#
        -sub NoExtension #(path)
        -    {
        -    my ($self, $path) = @_;
        -
        -    my $extension = $self->ExtensionOf($path);
        -
        -    if ($extension)
        -        {  $path = substr($path, 0, length($path) - length($extension) - 1);  };
        -
        -    return $path;
        -    };
        -
        -
        -#
        -#   Function: ExtensionOf
        -#
        -#   Returns the extension of the passed path, or undef if none.
        -#
        -sub ExtensionOf #(path)
        -    {
        -    my ($self, $path) = @_;
        -
        -    my ($pathVolume, $pathDirString, $pathFile) = File::Spec->splitpath($path);
        -
        -    # We need the leading dot in the regex so files that start with a dot but don't have an extension count as extensionless files.
        -    if ($pathFile =~ /.\.([^\.]+)$/)
        -        {  return $1;  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: IsCaseSensitive
        -#
        -#   Returns whether the current platform has case-sensitive paths.
        -#
        -sub IsCaseSensitive
        -    {
        -    return !(File::Spec->case_tolerant());
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Disk Functions
        -
        -
        -#
        -#   Function: CreatePath
        -#
        -#   Creates a directory tree corresponding to the passed path, regardless of how many directories do or do not already exist.
        -#   Do _not_ include a file name in the path.  Use <NoFileName()> first if you need to.
        -#
        -sub CreatePath #(path)
        -    {
        -    my ($self, $path) = @_;
        -    File::Path::mkpath($path);
        -    };
        -
        -
        -#
        -#   Function: RemoveEmptyTree
        -#
        -#   Removes an empty directory tree.  The passed directory will be removed if it's empty, and it will keep removing its parents
        -#   until it reaches one that's not empty or a set limit.
        -#
        -#   Parameters:
        -#
        -#       path - The path to start from.  It will try to remove this directory and work it's way down.
        -#       limit - The path to stop at if it doesn't find any non-empty directories first.  This path will *not* be removed.
        -#
        -sub RemoveEmptyTree #(path, limit)
        -    {
        -    my ($self, $path, $limit) = @_;
        -
        -    my ($volume, $directoryString) = $self->SplitPath($path, 1);
        -    my @directories = $self->SplitDirectories($directoryString);
        -
        -    my $directory = $path;
        -
        -    while (-d $directory && $directory ne $limit)
        -        {
        -        opendir FH_ND_FILE, $directory;
        -        my @entries = readdir FH_ND_FILE;
        -        closedir FH_ND_FILE;
        -
        -        @entries = $self->NoUpwards(@entries);
        -
        -        if (scalar @entries || !rmdir($directory))
        -            {  last;  };
        -
        -        pop @directories;
        -        $directoryString = $self->JoinDirectories(@directories);
        -        $directory = $self->JoinPath($volume, $directoryString);
        -        };
        -    };
        -
        -
        -#
        -#   Function: Copy
        -#
        -#   Copies a file from one path to another.  If the destination file exists, it is overwritten.
        -#
        -#   Parameters:
        -#
        -#       source       - The file to copy.
        -#       destination - The destination to copy to.
        -#
        -#   Returns:
        -#
        -#       Whether it succeeded
        -#
        -sub Copy #(source, destination) => bool
        -    {
        -    my ($self, $source, $destination) = @_;
        -    return File::Copy::copy($source, $destination);
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/ImageReferenceTable.pm b/vendor/naturaldocs/Modules/NaturalDocs/ImageReferenceTable.pm
        deleted file mode 100644
        index df803e4b5..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/ImageReferenceTable.pm
        +++ /dev/null
        @@ -1,384 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::ImageReferenceTable
        -#
        -###############################################################################
        -#
        -#   A <NaturalDocs::SourceDB>-based package that manages all the image references appearing in source files.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -use NaturalDocs::ImageReferenceTable::String;
        -use NaturalDocs::ImageReferenceTable::Reference;
        -
        -
        -package NaturalDocs::ImageReferenceTable;
        -
        -use base 'NaturalDocs::SourceDB::Extension';
        -
        -
        -###############################################################################
        -# Group: Information
        -
        -#
        -#   Topic: Usage
        -#
        -#       - <NaturalDocs::Project> and <NaturalDocs::SourceDB> must be initialized before this package can be used.
        -#
        -#       - Call <Register()> before using.
        -#
        -#
        -#   Topic: Programming Notes
        -#
        -#       When working on this code, remember that there are three things it has to juggle.
        -#
        -#       - The information in <NaturalDocs::SourceDB>.
        -#       - Image file references in <NaturalDocs::Project>.
        -#       - Source file rebuilding on changes.
        -#
        -#       Managing the actual image files will be handled between <NaturalDocs::Project> and the <NaturalDocs::Builder>
        -#       sub-packages.
        -#
        -#
        -#   Topic: Implementation
        -#
        -#       Managing image references is simpler than managing the references in <NaturalDocs::SymbolTable>.  In SymbolTable,
        -#       you have to worry about reference targets popping into and out of existence.  A link may go to a file that hasn't been
        -#       reparsed yet and the target may no longer exist.  We have to deal with that when we know it, which may be after the
        -#       reference's file was parsed.  Also, a new definition may appear that serves as a better interpretation of a link than its
        -#       current target, and again we may only know that after the reference's file has been parsed already.  So we have to deal
        -#       with scores and potential symbols and each symbol knowing exactly what links to it and so forth.
        -#
        -#       Not so with image references.  All possible targets (all possible image files) are known by <NaturalDocs::Project> early
        -#       on and will remain consistent throughout execution.  So because of that, we can get away with only storing reference
        -#       counts with each image and determining exactly where a reference points to as we find them.
        -#
        -#       Reference counts are stored with the image file information in <NaturalDocs::Project>.  However, it is not loaded and
        -#       saved to disk by it.  Rather, it is regenerated by this package when it loads <ImageReferenceTable.nd>.
        -#       NaturalDocs::Project only stores the last modification time (so it can add files to the build list if they've changed) and
        -#       whether it had any references at all on the last run (so it knows whether it should care if they've changed.)
        -#       ImageReferenceTable.nd stores each reference's target, width, and height.  Whether their interpretations have changed is
        -#       dealt with in the <Load()> function, again since the list of targets (image files) is constant.
        -#
        -#       The package is based on <NaturalDocs::SourceDB>, so read it's documentation for more information on how it works.
        -#
        -
        -
        -###############################################################################
        -# Group: Variables
        -
        -
        -#
        -#   var: extensionID
        -#   The <ExtensionID> granted by <NaturalDocs::SourceDB>.
        -#
        -my $extensionID;
        -
        -
        -
        -###############################################################################
        -# Group: Files
        -
        -
        -#
        -#   File: ImageReferenceTable.nd
        -#
        -#   The data file which stores all the image references from the last run of Natural Docs.
        -#
        -#   Format:
        -#
        -#       > [Standard Binary Header]
        -#
        -#       It starts with the standard binary header from <NaturalDocs::BinaryFile>.
        -#
        -#       > [Image Reference String or undef]
        -#       > [AString16: target file]
        -#       > [UInt16: target width or 0]
        -#       > [UInt16: target height or 0]
        -#
        -#       For each <ImageReferenceString>, it's target, width, and height are stored.  The target is needed so we can tell if it
        -#       changed from the last run, and the dimensions are needed because if the target hasn't changed but the file's dimensions
        -#       have, the source files need to be rebuilt.
        -#
        -#       <ImageReferenceStrings> are encoded by <NaturalDocs::ImageReferenceTable::String>.
        -#
        -#       > [AString16: definition file or undef] ...
        -#
        -#       Then comes a series of AString16s for all the files that define the reference until it hits an undef.
        -#
        -#       This whole series is repeated for each <ImageReferenceString> until it hits an undef.
        -#
        -#	Revisions:
        -#
        -#		1.4:
        -#
        -#			- The file was added to Natural Docs.
        -#
        -
        -
        -
        -###############################################################################
        -# Group: Functions
        -
        -
        -#
        -#   Function: Register
        -#   Registers the package with <NaturalDocs::SourceDB>.
        -#
        -sub Register
        -    {
        -    my $self = shift;
        -    $extensionID = NaturalDocs::SourceDB->RegisterExtension($self, 0);
        -    };
        -
        -
        -#
        -#   Function: Load
        -#
        -#   Loads the data from <ImageReferenceTable.nd>.  Returns whether it was successful.
        -#
        -sub Load # => bool
        -    {
        -    my $self = shift;
        -
        -    if (NaturalDocs::Settings->RebuildData())
        -        {  return 0;  };
        -
        -    # The file format hasn't changed since it was introduced.
        -    if (!NaturalDocs::BinaryFile->OpenForReading( NaturalDocs::Project->DataFile('ImageReferenceTable.nd') ))
        -        {  return 0;  };
        -
        -
        -    # [Image Reference String or undef]
        -    while (my $referenceString = NaturalDocs::ImageReferenceTable::String->FromBinaryFile())
        -        {
        -        NaturalDocs::SourceDB->AddItem($extensionID, $referenceString,
        -                                                           NaturalDocs::ImageReferenceTable::Reference->New());
        -
        -        # [AString16: target file]
        -        # [UInt16: target width or 0]
        -        # [UInt16: target height or 0]
        -
        -        my $targetFile = NaturalDocs::BinaryFile->GetAString16();
        -        my $width = NaturalDocs::BinaryFile->GetUInt16();
        -        my $height = NaturalDocs::BinaryFile->GetUInt16();
        -
        -        my $newTargetFile = $self->SetReferenceTarget($referenceString);
        -        my $newWidth;
        -        my $newHeight;
        -
        -        if ($newTargetFile)
        -            {
        -            NaturalDocs::Project->AddImageFileReference($newTargetFile);
        -            ($newWidth, $newHeight) = NaturalDocs::Project->ImageFileDimensions($newTargetFile);
        -            };
        -
        -        my $rebuildDefinitions = ($newTargetFile ne $targetFile || $newWidth != $width || $newHeight != $height);
        -
        -
        -        # [AString16: definition file or undef] ...
        -        while (my $definitionFile = NaturalDocs::BinaryFile->GetAString16())
        -            {
        -            NaturalDocs::SourceDB->AddDefinition($extensionID, $referenceString, $definitionFile);
        -
        -            if ($rebuildDefinitions)
        -                {  NaturalDocs::Project->RebuildFile($definitionFile);  };
        -            };
        -        };
        -
        -
        -    NaturalDocs::BinaryFile->Close();
        -    return 1;
        -    };
        -
        -
        -#
        -#   Function: Save
        -#
        -#   Saves the data to <ImageReferenceTable.nd>.
        -#
        -sub Save
        -    {
        -    my $self = shift;
        -
        -    my $references = NaturalDocs::SourceDB->GetAllItemsHashRef($extensionID);
        -
        -    NaturalDocs::BinaryFile->OpenForWriting( NaturalDocs::Project->DataFile('ImageReferenceTable.nd') );
        -
        -    while (my ($referenceString, $referenceObject) = each %$references)
        -        {
        -        # [Image Reference String or undef]
        -        # [AString16: target file]
        -        # [UInt16: target width or 0]
        -        # [UInt16: target height or 0]
        -
        -        NaturalDocs::ImageReferenceTable::String->ToBinaryFile($referenceString);
        -
        -        my $target = $referenceObject->Target();
        -        my ($width, $height);
        -
        -        if ($target)
        -            {  ($width, $height) = NaturalDocs::Project->ImageFileDimensions($target);  };
        -
        -        NaturalDocs::BinaryFile->WriteAString16( $referenceObject->Target() );
        -        NaturalDocs::BinaryFile->WriteUInt16( ($width || 0) );
        -        NaturalDocs::BinaryFile->WriteUInt16( ($height || 0) );
        -
        -        # [AString16: definition file or undef] ...
        -
        -        my $definitions = $referenceObject->GetAllDefinitionsHashRef();
        -
        -        foreach my $definition (keys %$definitions)
        -            {  NaturalDocs::BinaryFile->WriteAString16($definition);  };
        -
        -        NaturalDocs::BinaryFile->WriteAString16(undef);
        -        };
        -
        -    NaturalDocs::ImageReferenceTable::String->ToBinaryFile(undef);
        -
        -    NaturalDocs::BinaryFile->Close();
        -    };
        -
        -
        -#
        -#   Function: AddReference
        -#
        -#   Adds a new image reference.
        -#
        -sub AddReference #(FileName file, string referenceText)
        -    {
        -    my ($self, $file, $referenceText) = @_;
        -
        -    my $referenceString = NaturalDocs::ImageReferenceTable::String->Make($file, $referenceText);
        -
        -    if (!NaturalDocs::SourceDB->HasItem($extensionID, $referenceString))
        -        {
        -        my $referenceObject = NaturalDocs::ImageReferenceTable::Reference->New();
        -        NaturalDocs::SourceDB->AddItem($extensionID, $referenceString, $referenceObject);
        -
        -        my $target = $self->SetReferenceTarget($referenceString);
        -        if ($target)
        -            {  NaturalDocs::Project->AddImageFileReference($target);  };
        -        };
        -
        -    NaturalDocs::SourceDB->AddDefinition($extensionID, $referenceString, $file);
        -    };
        -
        -
        -#
        -#   Function: OnDeletedDefinition
        -#
        -#   Called for each definition deleted by <NaturalDocs::SourceDB>.  This is called *after* the definition has been deleted from
        -#   the database, so don't expect to be able to read it.
        -#
        -sub OnDeletedDefinition #(ImageReferenceString referenceString, FileName file, bool wasLastDefinition)
        -    {
        -    my ($self, $referenceString, $file, $wasLastDefinition) = @_;
        -
        -    if ($wasLastDefinition)
        -        {
        -        my $referenceObject = NaturalDocs::SourceDB->GetItem($extensionID, $referenceString);
        -        my $target = $referenceObject->Target();
        -
        -        if ($target)
        -            {  NaturalDocs::Project->DeleteImageFileReference($target);  };
        -
        -        NaturalDocs::SourceDB->DeleteItem($extensionID, $referenceString);
        -        };
        -    };
        -
        -
        -#
        -#   Function: GetReferenceTarget
        -#
        -#   Returns the image file the reference resolves to, or undef if none.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The source <FileName> the reference appears in.
        -#       text - The reference text.
        -#
        -sub GetReferenceTarget #(FileName sourceFile, string text) => FileName
        -    {
        -    my ($self, $sourceFile, $text) = @_;
        -
        -    my $referenceString = NaturalDocs::ImageReferenceTable::String->Make($sourceFile, $text);
        -    my $reference = NaturalDocs::SourceDB->GetItem($extensionID, $referenceString);
        -
        -    if (!defined $reference)
        -        {  return undef;  }
        -    else
        -        {  return $reference->Target();  };
        -    };
        -
        -
        -#
        -#   Function: SetReferenceTarget
        -#
        -#   Determines the best target for the passed <ImageReferenceString> and sets it on the
        -#   <NaturalDocs::ImageReferenceTable::Reference> object.  Returns the new target <FileName>.  Does *not* add any source
        -#   files to the bulid list.
        -#
        -sub SetReferenceTarget #(ImageReferenceString referenceString) => FileName
        -    {
        -    my ($self, $referenceString) = @_;
        -
        -    my $referenceObject = NaturalDocs::SourceDB->GetItem($extensionID, $referenceString);
        -    my ($sourcePath, $text) = NaturalDocs::ImageReferenceTable::String->InformationOf($referenceString);
        -
        -
        -    # Try the path relative to the source file first.
        -
        -    my $target;
        -
        -    my $imageFile = NaturalDocs::File->JoinPaths($sourcePath, $text);
        -    my $exists = NaturalDocs::Project->ImageFileExists($imageFile);
        -
        -
        -    # Then try relative image directories.
        -
        -    if (!$exists)
        -        {
        -        my $relativeImageDirectories = NaturalDocs::Settings->RelativeImageDirectories();
        -
        -        for (my $i = 0; $i < scalar @$relativeImageDirectories && !$exists; $i++)
        -            {
        -            $imageFile = NaturalDocs::File->JoinPaths($sourcePath, $relativeImageDirectories->[$i], 1);
        -            $imageFile = NaturalDocs::File->JoinPaths($imageFile, $text);
        -
        -            $exists = NaturalDocs::Project->ImageFileExists($imageFile);
        -            };
        -        };
        -
        -
        -    # Then try absolute image directories.
        -
        -    if (!$exists)
        -        {
        -        my $imageDirectories = NaturalDocs::Settings->ImageDirectories();
        -
        -        for (my $i = 0; $i < scalar @$imageDirectories && !$exists; $i++)
        -            {
        -            $imageFile = NaturalDocs::File->JoinPaths($imageDirectories->[$i], $text);
        -            $exists = NaturalDocs::Project->ImageFileExists($imageFile);
        -            };
        -        };
        -
        -
        -    if ($exists)
        -        {  $target = NaturalDocs::Project->ImageFileCapitalization($imageFile);  };
        -    #else leave it as undef.
        -
        -    $referenceObject->SetTarget($target);
        -    return $target;
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/ImageReferenceTable/Reference.pm b/vendor/naturaldocs/Modules/NaturalDocs/ImageReferenceTable/Reference.pm
        deleted file mode 100644
        index 3477435af..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/ImageReferenceTable/Reference.pm
        +++ /dev/null
        @@ -1,45 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::ImageReferenceTable::Reference
        -#
        -###############################################################################
        -#
        -#   A class for references being tracked in <NaturalDocs::SourceDB>.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -
        -package NaturalDocs::ImageReferenceTable::Reference;
        -
        -use base 'NaturalDocs::SourceDB::Item';
        -
        -
        -use NaturalDocs::DefineMembers 'TARGET', 'Target()', 'SetTarget()',
        -                                                 'NEEDS_REBUILD', 'NeedsRebuild()', 'SetNeedsRebuild()';
        -
        -
        -#
        -#   Variables: Members
        -#
        -#   The following constants are indexes into the object array.
        -#
        -#   TARGET - The image <FileName> this reference resolves to, or undef if none.
        -#
        -
        -
        -#
        -#   Functions: Member Functions
        -#
        -#   Target - Returns the image <FileName> this reference resolves to, or undef if none.
        -#   SetTarget - Replaces the image <FileName> this reference resolves to, or undef if none.
        -#
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/ImageReferenceTable/String.pm b/vendor/naturaldocs/Modules/NaturalDocs/ImageReferenceTable/String.pm
        deleted file mode 100644
        index 27fbf7797..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/ImageReferenceTable/String.pm
        +++ /dev/null
        @@ -1,111 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::ImageReferenceTable::String
        -#
        -###############################################################################
        -#
        -#   A package for creating and managing <ImageReferenceStrings>.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -
        -package NaturalDocs::ImageReferenceTable::String;
        -
        -
        -#
        -#   Type: ImageReferenceString
        -#
        -#   A string representing a unique image reference.  It's composed of the reference text and the directory of the source file.
        -#   The source file name itself isn't included because two files in the same directory with the same reference text will always go
        -#   to the same targets.
        -#
        -
        -
        -#
        -#   Function: Make
        -#
        -#   Converts a source <FileName> and the reference text to an <ImageReferenceString>.
        -#
        -sub Make #(FileName sourceFile, string text) => ImageReferenceString
        -    {
        -    my ($self, $sourceFile, $text) = @_;
        -
        -    my $path = NaturalDocs::File->NoFileName($sourceFile);
        -
        -    # Condense whitespace and remove any separator characters.
        -    $path =~ tr/ \t\r\n\x1C/ /s;
        -    $text =~ tr/ \t\r\n\x1C/ /s;
        -
        -    return $path . "\x1C" . $text;
        -    };
        -
        -
        -#
        -#   Function: InformationOf
        -#
        -#   Returns the information contained in the <ImageReferenceString> as the array ( path, text ).
        -#
        -sub InformationOf #(ImageReferenceString referenceString)
        -    {
        -    my ($self, $referenceString) = @_;
        -    return split(/\x1C/, $referenceString);
        -    };
        -
        -
        -#
        -#   Function: ToBinaryFile
        -#
        -#   Writes an <ImageReferenceString> to <NaturalDocs::BinaryFile>.  Can also encode an undef.
        -#
        -#   Format:
        -#
        -#       > [AString16: path] [AString16: reference text] ...
        -#
        -#       Undef is represented by the first AString16 being undef.
        -#
        -sub ToBinaryFile #(ImageReferenceString referenceString)
        -    {
        -    my ($self, $referenceString) = @_;
        -
        -    if (defined $referenceString)
        -        {
        -        my ($path, $text) = split(/\x1C/, $referenceString);
        -
        -        NaturalDocs::BinaryFile->WriteAString16($path);
        -        NaturalDocs::BinaryFile->WriteAString16($text);
        -        }
        -    else
        -        {
        -        NaturalDocs::BinaryFile->WriteAString16(undef);
        -        };
        -    };
        -
        -
        -#
        -#   Function: FromBinaryFile
        -#
        -#   Loads an <ImageReferenceString> or undef from <NaturalDocs::BinaryFile> and returns it.
        -#
        -sub FromBinaryFile
        -    {
        -    my $self = shift;
        -
        -    my $path = NaturalDocs::BinaryFile->GetAString16();
        -
        -    if (!defined $path)
        -        {  return undef;  };
        -
        -    my $text = NaturalDocs::BinaryFile->GetAString16();
        -
        -    return $path . "\x1C" . $text;
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages.pm
        deleted file mode 100644
        index a85f749f4..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages.pm
        +++ /dev/null
        @@ -1,1476 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Languages
        -#
        -###############################################################################
        -#
        -#   A package to manage all the programming languages Natural Docs supports.
        -#
        -#   Usage and Dependencies:
        -#
        -#       - Prior to use, <NaturalDocs::Settings> must be initialized and <Load()> must be called.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use Text::Wrap();
        -
        -use NaturalDocs::Languages::Prototype;
        -
        -use NaturalDocs::Languages::Base;
        -use NaturalDocs::Languages::Simple;
        -use NaturalDocs::Languages::Advanced;
        -
        -use NaturalDocs::Languages::Perl;
        -use NaturalDocs::Languages::CSharp;
        -use NaturalDocs::Languages::ActionScript;
        -
        -use NaturalDocs::Languages::Ada;
        -use NaturalDocs::Languages::PLSQL;
        -use NaturalDocs::Languages::Pascal;
        -use NaturalDocs::Languages::Tcl;
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Languages;
        -
        -
        -###############################################################################
        -# Group: Variables
        -
        -
        -#
        -#   handle: FH_LANGUAGES
        -#
        -#   The file handle used for writing to <Languages.txt>.
        -#
        -
        -
        -#
        -#   hash: languages
        -#
        -#   A hash of all the defined languages.  The keys are the all-lowercase language names, and the values are
        -#   <NaturalDocs::Languages::Base>-derived objects.
        -#
        -my %languages;
        -
        -#
        -#   hash: extensions
        -#
        -#   A hash of all the defined languages' extensions.  The keys are the all-lowercase extensions, and the values are the
        -#   all-lowercase names of the languages that defined them.
        -#
        -my %extensions;
        -
        -#
        -#   hash: shebangStrings
        -#
        -#   A hash of all the defined languages' strings to search for in the shebang (#!) line.  The keys are the all-lowercase strings, and
        -#   the values are the all-lowercase names of the languages that defined them.
        -#
        -my %shebangStrings;
        -
        -#
        -#   hash: shebangFiles
        -#
        -#   A hash of all the defined languages for files where it needs to be found via shebang strings.  The keys are the file names,
        -#   and the values are language names, or undef if the file isn't supported.  These values should be filled in the first time
        -#   each file is parsed for a shebang string so that it doesn't have to be done multiple times.
        -#
        -my %shebangFiles;
        -
        -#
        -#   array: mainLanguageNames
        -#
        -#   An array of the language names that are defined in the main <Languages.txt>.
        -#
        -my @mainLanguageNames;
        -
        -
        -
        -###############################################################################
        -# Group: Files
        -
        -
        -#
        -#   File: Languages.txt
        -#
        -#   The configuration file that defines or overrides the language definitions for Natural Docs.  One version sits in Natural Docs'
        -#   configuration directory, and another can be in a project directory to add to or override them.
        -#
        -#   > # [comments]
        -#
        -#   Everything after a # symbol is ignored.  However, for this particular file, comments can only appear on their own lines.
        -#   They cannot appear after content on the same line.
        -#
        -#   > Format: [version]
        -#
        -#   Specifies the file format version of the file.
        -#
        -#
        -#   Sections:
        -#
        -#       > Ignore[d] Extension[s]: [extension] [extension] ...
        -#
        -#       Causes the listed file extensions to be ignored, even if they were previously defined to be part of a language.  The list is
        -#       space-separated.  ex. "Ignore Extensions: cvs txt"
        -#
        -#
        -#       > Language: [name]
        -#
        -#       Creates a new language.  Everything underneath applies to this language until the next one.  Names can use any
        -#       characters.
        -#
        -#       The languages "Text File" and "Shebang Script" have special meanings.  Text files are considered all comment and don't
        -#       have comment symbols.  Shebang scripts have their language determined by the shebang string and automatically
        -#       include files with no extension in addition to the extensions defined.
        -#
        -#       If "Text File" doesn't define ignored prefixes, a package separator, or enum value behavior, those settings will be copied
        -#       from the language with the most files in the source tree.
        -#
        -#
        -#       > Alter Language: [name]
        -#
        -#       Alters an existing language.  Everything underneath it overrides the previous settings until the next one.  Note that if a
        -#       property has an [Add/Replace] form and that property has already been defined, you have to specify whether you're adding
        -#       to or replacing the defined list.
        -#
        -#
        -#   Language Properties:
        -#
        -#       > Extension[s]: [extension] [extension] ...
        -#       > [Add/Replace] Extension[s]: ...
        -#
        -#       Defines file extensions for the language's source files.  The list is space-separated.  ex. "Extensions: c cpp".  You can use
        -#       extensions that were previously used by another language to redefine them.
        -#
        -#
        -#       > Shebang String[s]: [string] [string] ...
        -#       > [Add/Replace] Shebang String[s]: ...
        -#
        -#       Defines a list of strings that can appear in the shebang (#!) line to designate that it's part of this language.  They can
        -#       appear anywhere in the line, so "php" will work for "#!/user/bin/php4".  You can use strings that were previously used by
        -#       another language to redefine them.
        -#
        -#
        -#       > Ignore[d] Prefix[es] in Index: [prefix] [prefix] ...
        -#       > Ignore[d] [Topic Type] Prefix[es] in Index: [prefix] [prefix] ...
        -#       > [Add/Replace] Ignore[d] Prefix[es] in Index: ...
        -#       > [Add/Replace] Ignore[d] [Topic Type] Prefix[es] in Index: ...
        -#
        -#       Specifies prefixes that should be ignored when sorting symbols for an index.  Can be specified in general or for a specific
        -#       <TopicType>.  The prefixes will still appear, the symbols will just be sorted as if they're not there.  For example, specifying
        -#       "ADO_" for functions will mean that "ADO_DoSomething" will appear under D instead of A.
        -#
        -#
        -#   Basic Language Support Properties:
        -#
        -#       These attributes are only available for languages with basic language support.
        -#
        -#
        -#       > Line Comment[s]: [symbol] [symbol] ...
        -#
        -#       Defines a space-separated list of symbols that are used for line comments, if any.  ex. "Line Comment: //".
        -#
        -#
        -#       > Block Comment[s]: [opening symbol] [closing symbol] [opening symbol] [closing symbol] ...
        -#
        -#       Defines a space-separated list of symbol pairs that are used for block comments, if any.  ex. "Block Comment: /* */".
        -#
        -#
        -#       > Package Separator: [symbol]
        -#
        -#       Defines the default package separator symbol, such as . or ::.  This is for presentation only and will not affect how
        -#       Natural Docs links are parsed.  The default is a dot.
        -#
        -#
        -#       > [Topic Type] Prototype Ender[s]: [symbol] [symbol] ...
        -#
        -#       When defined, Natural Docs will attempt to collect prototypes from the code following the specified <TopicType>.  It grabs
        -#       code until the first ender symbol or the next Natural Docs comment, and if it contains the topic name, it serves as its
        -#       prototype.  Use \n to specify a line break.  ex. "Function Prototype Enders: { ;", "Variable Prototype Enders: = ;".
        -#
        -#
        -#       > Line Extender: [symbol]
        -#
        -#       Defines the symbol that allows a prototype to span multiple lines if normally a line break would end it.
        -#
        -#
        -#       > Enum Values: [global|under type|under parent]
        -#
        -#       Defines how enum values are referenced.  The default is global.
        -#
        -#       global - Values are always global, referenced as 'value'.
        -#       under type - Values are under the enum type, referenced as 'package.enum.value'.
        -#       under parent - Values are under the enum's parent, referenced as 'package.value'.
        -#
        -#
        -#       > Perl Package: [perl package]
        -#
        -#       Specifies the Perl package used to fine-tune the language behavior in ways too complex to do in this file.
        -#
        -#
        -#   Full Language Support Properties:
        -#
        -#       These attributes are only available for languages with full language support.
        -#
        -#
        -#       > Full Language Support: [perl package]
        -#
        -#       Specifies the Perl package that has the parsing routines necessary for full language support.
        -#
        -#
        -#   Revisions:
        -#
        -#       1.32:
        -#
        -#           - Package Separator is now a basic language support only property.
        -#           - Added Enum Values setting.
        -#
        -#       1.3:
        -#
        -#           - The file was introduced.
        -
        -
        -###############################################################################
        -# Group: File Functions
        -
        -
        -#
        -#   Function: Load
        -#
        -#   Loads both the master and the project version of <Languages.txt>.
        -#
        -sub Load
        -    {
        -    my $self = shift;
        -
        -    # Hashrefs where the keys are all-lowercase extensions/shebang strings, and the values are arrayrefs of the languages
        -    # that defined them, earliest first, all lowercase.
        -    my %tempExtensions;
        -    my %tempShebangStrings;
        -
        -    $self->LoadFile(1, \%tempExtensions, \%tempShebangStrings);  # Main
        -
        -    if (!exists $languages{'shebang script'})
        -        {  NaturalDocs::ConfigFile->AddError('You must define "Shebang Script" in the main languages file.');  };
        -    if (!exists $languages{'text file'})
        -        {  NaturalDocs::ConfigFile->AddError('You must define "Text File" in the main languages file.');  };
        -
        -    my $errorCount = NaturalDocs::ConfigFile->ErrorCount();
        -
        -    if ($errorCount)
        -        {
        -        NaturalDocs::ConfigFile->PrintErrorsAndAnnotateFile();
        -        NaturalDocs::Error->SoftDeath('There ' . ($errorCount == 1 ? 'is an error' : 'are ' . $errorCount . ' errors')
        -                                                    . ' in ' . NaturalDocs::Project->MainConfigFile('Languages.txt'));
        -        }
        -
        -
        -    $self->LoadFile(0, \%tempExtensions, \%tempShebangStrings);  # User
        -
        -    $errorCount = NaturalDocs::ConfigFile->ErrorCount();
        -
        -    if ($errorCount)
        -        {
        -        NaturalDocs::ConfigFile->PrintErrorsAndAnnotateFile();
        -        NaturalDocs::Error->SoftDeath('There ' . ($errorCount == 1 ? 'is an error' : 'are ' . $errorCount . ' errors')
        -                                                    . ' in ' . NaturalDocs::Project->UserConfigFile('Languages.txt'));
        -        };
        -
        -
        -    # Convert the temp hashes into the real ones.
        -
        -    while (my ($extension, $languages) = each %tempExtensions)
        -        {
        -        $extensions{$extension} = $languages->[-1];
        -        };
        -    while (my ($shebangString, $languages) = each %tempShebangStrings)
        -        {
        -        $shebangStrings{$shebangString} = $languages->[-1];
        -        };
        -    };
        -
        -
        -#
        -#   Function: LoadFile
        -#
        -#   Loads a particular version of <Languages.txt>.
        -#
        -#   Parameters:
        -#
        -#       isMain - Whether the file is the main file or not.
        -#       tempExtensions - A hashref where the keys are all-lowercase extensions, and the values are arrayrefs of the all-lowercase
        -#                                 names of the languages that defined them, earliest first.  It will be changed by this function.
        -#       tempShebangStrings - A hashref where the keys are all-lowercase shebang strings, and the values are arrayrefs of the
        -#                                        all-lowercase names of the languages that defined them, earliest first.  It will be changed by this
        -#                                        function.
        -#
        -sub LoadFile #(isMain, tempExtensions, tempShebangStrings)
        -    {
        -    my ($self, $isMain, $tempExtensions, $tempShebangStrings) = @_;
        -
        -    my ($file, $status);
        -
        -    if ($isMain)
        -        {
        -        $file = NaturalDocs::Project->MainConfigFile('Languages.txt');
        -        $status = NaturalDocs::Project->MainConfigFileStatus('Languages.txt');
        -        }
        -    else
        -        {
        -        $file = NaturalDocs::Project->UserConfigFile('Languages.txt');
        -        $status = NaturalDocs::Project->UserConfigFileStatus('Languages.txt');
        -        };
        -
        -
        -    my $version;
        -
        -    # An array of properties for the current language.  Each entry is the three consecutive values ( lineNumber, keyword, value ).
        -    my @properties;
        -
        -    if ($version = NaturalDocs::ConfigFile->Open($file))
        -        {
        -        # The format hasn't changed significantly since the file was introduced.
        -
        -        if ($status == ::FILE_CHANGED())
        -            {
        -            NaturalDocs::Project->ReparseEverything();
        -            NaturalDocs::SymbolTable->RebuildAllIndexes();  # Because the ignored prefixes could change.
        -            };
        -
        -        my ($keyword, $value, $comment);
        -
        -        while (($keyword, $value, $comment) = NaturalDocs::ConfigFile->GetLine())
        -            {
        -            $value .= $comment;
        -            $value =~ s/^ //;
        -
        -            # Process previous properties.
        -            if (($keyword eq 'language' || $keyword eq 'alter language') && scalar @properties)
        -                {
        -                if ($isMain && $properties[1] eq 'language')
        -                    {  push @mainLanguageNames, $properties[2];  };
        -
        -                $self->ProcessProperties(\@properties, $version, $tempExtensions, $tempShebangStrings);
        -                @properties = ( );
        -                };
        -
        -            if ($keyword =~ /^ignored? extensions?$/)
        -                {
        -                $value =~ tr/.*//d;
        -                my @extensions = split(/ /, lc($value));
        -
        -                foreach my $extension (@extensions)
        -                    {  delete $tempExtensions->{$extension};  };
        -                }
        -            else
        -                {
        -                push @properties, NaturalDocs::ConfigFile->LineNumber(), $keyword, $value;
        -                };
        -            };
        -
        -        if (scalar @properties)
        -            {
        -            if ($isMain && $properties[1] eq 'language')
        -                {  push @mainLanguageNames, $properties[2];  };
        -
        -            $self->ProcessProperties(\@properties, $version, $tempExtensions, $tempShebangStrings);
        -            };
        -        }
        -
        -    else # couldn't open file
        -        {
        -        if ($isMain)
        -            {  die "Couldn't open languages file " . $file . "\n";  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: ProcessProperties
        -#
        -#   Processes an array of language properties from <Languages.txt>.
        -#
        -#   Parameters:
        -#
        -#       properties - An arrayref of properties where each entry is the three consecutive values ( lineNumber, keyword, value ).
        -#                         It must start with the Language or Alter Language property.
        -#       version - The <VersionInt> of the file.
        -#       tempExtensions - A hashref where the keys are all-lowercase extensions, and the values are arrayrefs of the all-lowercase
        -#                                 names of the languages that defined them, earliest first.  It will be changed by this function.
        -#       tempShebangStrings - A hashref where the keys are all-lowercase shebang strings, and the values are arrayrefs of the
        -#                                        all-lowercase names of the languages that defined them, earliest first.  It will be changed by this
        -#                                        function.
        -#
        -sub ProcessProperties #(properties, version, tempExtensions, tempShebangStrings)
        -    {
        -    my ($self, $properties, $version, $tempExtensions, $tempShebangStrings) = @_;
        -
        -
        -    # First validate the name and check whether the language has full support.
        -
        -    my $language;
        -    my $fullLanguageSupport;
        -    my ($lineNumber, $languageKeyword, $languageName) = @$properties[0..2];
        -    my $lcLanguageName = lc($languageName);
        -    my ($keyword, $value);
        -
        -    if ($languageKeyword eq 'alter language')
        -        {
        -        $language = $languages{$lcLanguageName};
        -
        -        if (!defined $language)
        -            {
        -            NaturalDocs::ConfigFile->AddError('The language ' . $languageName . ' is not defined.', $lineNumber);
        -            return;
        -            }
        -        else
        -            {
        -            $fullLanguageSupport = (!$language->isa('NaturalDocs::Languages::Simple'));
        -            };
        -        }
        -
        -    elsif ($languageKeyword eq 'language')
        -        {
        -        if (exists $languages{$lcLanguageName})
        -            {
        -            NaturalDocs::ConfigFile->AddError('The language ' . $value . ' is already defined.  Use "Alter Language" if you want '
        -                                                             . 'to override its settings.', $lineNumber);
        -            return;
        -            };
        -
        -        # Case is important with these two.
        -        if ($lcLanguageName eq 'shebang script')
        -            {  $languageName = 'Shebang Script';  }
        -        elsif ($lcLanguageName eq 'text file')
        -            {  $languageName = 'Text File';  };
        -
        -
        -        # Go through the properties looking for whether the language has basic or full support and which package to use to create
        -        # it.
        -
        -        for (my $i = 3; $i < scalar @$properties; $i += 3)
        -            {
        -            ($lineNumber, $keyword, $value) = @$properties[$i..$i+2];
        -
        -            if ($keyword eq 'full language support')
        -                {
        -                $fullLanguageSupport = 1;
        -
        -                eval
        -                    {
        -                    $language = $value->New($languageName);
        -                    };
        -                if ($::EVAL_ERROR)
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('Could not create ' . $value . ' object.', $lineNumber);
        -                    return;
        -                    };
        -
        -                last;
        -                }
        -
        -            elsif ($keyword eq 'perl package')
        -                {
        -                eval
        -                    {
        -                    $language = $value->New($languageName);
        -                    };
        -                if ($::EVAL_ERROR)
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('Could not create ' . $value . ' object.', $lineNumber);
        -                    return;
        -                    };
        -                };
        -            };
        -
        -        # If $language was not created by now, it's a generic basic support language.
        -        if (!defined $language)
        -            {  $language = NaturalDocs::Languages::Simple->New($languageName);  };
        -
        -        $languages{$lcLanguageName} = $language;
        -        }
        -
        -    else # not language or alter language
        -        {
        -        NaturalDocs::ConfigFile->AddError('You must start this line with "Language", "Alter Language", or "Ignore Extensions".',
        -                                                           $lineNumber);
        -        return;
        -        };
        -
        -
        -    # Decode the properties.
        -
        -    for (my $i = 3; $i < scalar @$properties; $i += 3)
        -        {
        -        ($lineNumber, $keyword, $value) = @$properties[$i..$i+2];
        -
        -        if ($keyword =~ /^(?:(add|replace) )?extensions?$/)
        -            {
        -            my $command = $1;
        -
        -
        -            # Remove old extensions.
        -
        -            if (defined $language->Extensions() && $command eq 'replace')
        -                {
        -                foreach my $extension (@{$language->Extensions()})
        -                    {
        -                    if (exists $tempExtensions->{$extension})
        -                        {
        -                        my $languages = $tempExtensions->{$extension};
        -                        my $i = 0;
        -
        -                        while ($i < scalar @$languages)
        -                            {
        -                            if ($languages->[$i] eq $lcLanguageName)
        -                                {  splice(@$languages, $i, 1);  }
        -                            else
        -                                {  $i++;  };
        -                            };
        -
        -                        if (!scalar @$languages)
        -                            {  delete $tempExtensions->{$extension};  };
        -                        };
        -                    };
        -                };
        -
        -
        -            # Add new extensions.
        -
        -            # Ignore stars and dots so people could use .ext or *.ext.
        -            $value =~ s/\*\.|\.//g;
        -
        -            my @extensions = split(/ /, lc($value));
        -
        -            foreach my $extension (@extensions)
        -                {
        -                if (!exists $tempExtensions->{$extension})
        -                    {  $tempExtensions->{$extension} = [ ];  };
        -
        -                push @{$tempExtensions->{$extension}}, $lcLanguageName;
        -                };
        -
        -
        -            # Set the extensions for the language object.
        -
        -            if (defined $language->Extensions())
        -                {
        -                if ($command eq 'add')
        -                    {  push @extensions, @{$language->Extensions()};  }
        -                elsif (!$command)
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('You need to specify whether you are adding to or replacing the list of extensions.',
        -                                                                       $lineNumber);
        -                    };
        -                };
        -
        -            $language->SetExtensions(\@extensions);
        -            }
        -
        -        elsif ($keyword =~ /^(?:(add|replace) )?shebang strings?$/)
        -            {
        -            my $command = $1;
        -
        -
        -            # Remove old strings.
        -
        -            if (defined $language->ShebangStrings() && $command eq 'replace')
        -                {
        -                foreach my $shebangString (@{$language->ShebangStrings()})
        -                    {
        -                    if (exists $tempShebangStrings->{$shebangString})
        -                        {
        -                        my $languages = $tempShebangStrings->{$shebangString};
        -                        my $i = 0;
        -
        -                        while ($i < scalar @$languages)
        -                            {
        -                            if ($languages->[$i] eq $lcLanguageName)
        -                                {  splice(@$languages, $i, 1);  }
        -                            else
        -                                {  $i++;  };
        -                            };
        -
        -                        if (!scalar @$languages)
        -                            {  delete $tempShebangStrings->{$shebangString};  };
        -                        };
        -                    };
        -                };
        -
        -
        -            # Add new strings.
        -
        -            my @shebangStrings = split(/ /, lc($value));
        -
        -            foreach my $shebangString (@shebangStrings)
        -                {
        -                if (!exists $tempShebangStrings->{$shebangString})
        -                    {  $tempShebangStrings->{$shebangString} = [ ];  };
        -
        -                push @{$tempShebangStrings->{$shebangString}}, $lcLanguageName;
        -                };
        -
        -
        -            # Set the strings for the language object.
        -
        -            if (defined $language->ShebangStrings())
        -                {
        -                if ($command eq 'add')
        -                    {  push @shebangStrings, @{$language->ShebangStrings()};  }
        -                elsif (!$command)
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('You need to specify whether you are adding to or replacing the list of shebang '
        -                                                                     . 'strings.', $lineNumber);
        -                    };
        -                };
        -
        -            $language->SetShebangStrings(\@shebangStrings);
        -            }
        -
        -        elsif ($keyword eq 'package separator')
        -            {
        -            if ($fullLanguageSupport)
        -                {
        -                # Prior to 1.32, package separator was used with full language support too.  Accept it without complaining, even though
        -                # we ignore it.
        -                if ($version >= NaturalDocs::Version->FromString('1.32'))
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('You cannot define this property when using full language support.', $lineNumber);
        -                    };
        -                }
        -            else
        -                {  $language->SetPackageSeparator($value);  };
        -            }
        -
        -        elsif ($keyword =~ /^(?:(add|replace) )?ignored? (?:(.+) )?prefix(?:es)? in index$/)
        -            {
        -            my ($command, $topicName) = ($1, $2);
        -            my $topicType;
        -
        -            if ($topicName)
        -                {
        -                if (!( ($topicType, undef) = NaturalDocs::Topics->NameInfo($topicName) ))
        -                    {
        -                    NaturalDocs::ConfigFile->AddError($topicName . ' is not a defined topic type.', $lineNumber);
        -                    };
        -                }
        -            else
        -                {  $topicType = ::TOPIC_GENERAL();  };
        -
        -            if ($topicType)
        -                {
        -                my @prefixes;
        -
        -                if (defined $language->IgnoredPrefixesFor($topicType))
        -                    {
        -                    if ($command eq 'add')
        -                        {  @prefixes = @{$language->IgnoredPrefixesFor($topicType)};  }
        -                    elsif (!$command)
        -                        {
        -                        NaturalDocs::ConfigFile->AddError('You need to specify whether you are adding to or replacing the list of '
        -                                                                         . 'ignored prefixes.', $lineNumber);
        -                        };
        -                    };
        -
        -                push @prefixes, split(/ /, $value);
        -                $language->SetIgnoredPrefixesFor($topicType, \@prefixes);
        -                };
        -            }
        -
        -        elsif ($keyword eq 'full language support' || $keyword eq 'perl package')
        -            {
        -            if ($languageKeyword eq 'alter language')
        -                {
        -                NaturalDocs::ConfigFile->AddError('You cannot use ' . $keyword . ' with Alter Language.', $lineNumber);
        -                };
        -            # else ignore it.
        -            }
        -
        -        elsif ($keyword =~ /^line comments?$/)
        -            {
        -            if ($fullLanguageSupport)
        -                {
        -                NaturalDocs::ConfigFile->AddError('You cannot define this property when using full language support.', $lineNumber);
        -                }
        -            else
        -                {
        -                my @symbols = split(/ /, $value);
        -                $language->SetLineCommentSymbols(\@symbols);
        -                };
        -            }
        -
        -        elsif ($keyword =~ /^block comments?$/)
        -            {
        -            if ($fullLanguageSupport)
        -                {
        -                NaturalDocs::ConfigFile->AddError('You cannot define this property when using full language support.', $lineNumber);
        -                }
        -            else
        -                {
        -                my @symbols = split(/ /, $value);
        -
        -                if ((scalar @symbols) % 2 == 0)
        -                    {  $language->SetBlockCommentSymbols(\@symbols);  }
        -                else
        -                    {  NaturalDocs::ConfigFile->AddError('Block comment symbols must appear in pairs.', $lineNumber);  };
        -                };
        -            }
        -
        -        elsif ($keyword =~ /^(?:(.+) )?prototype enders?$/)
        -            {
        -            if ($fullLanguageSupport)
        -                {
        -                NaturalDocs::ConfigFile->AddError('You cannot define this property when using full language support.', $lineNumber);
        -                }
        -            else
        -                {
        -                my $topicName = $1;
        -                my $topicType;
        -
        -                if ($topicName)
        -                    {
        -                    if (!( ($topicType, undef) = NaturalDocs::Topics->NameInfo($topicName) ))
        -                        {
        -                        NaturalDocs::ConfigFile->AddError($topicName . ' is not a defined topic type.', $lineNumber);
        -                        };
        -                    }
        -                else
        -                    {  $topicType = ::TOPIC_GENERAL();  };
        -
        -                if ($topicType)
        -                    {
        -                    $value =~ s/\\n/\n/g;
        -                    my @symbols = split(/ /, $value);
        -                    $language->SetPrototypeEndersFor($topicType, \@symbols);
        -                    };
        -                };
        -            }
        -
        -        elsif ($keyword eq 'line extender')
        -            {
        -            if ($fullLanguageSupport)
        -                {
        -                NaturalDocs::ConfigFile->AddError('You cannot define this property when using full language support.', $lineNumber);
        -                }
        -            else
        -                {
        -                $language->SetLineExtender($value);
        -                };
        -            }
        -
        -        elsif ($keyword eq 'enum values')
        -            {
        -            if ($fullLanguageSupport)
        -                {
        -                NaturalDocs::ConfigFile->AddError('You cannot define this property when using full language support.', $lineNumber);
        -                }
        -            else
        -                {
        -                $value = lc($value);
        -                my $constant;
        -
        -                if ($value eq 'global')
        -                    {  $constant = ::ENUM_GLOBAL();  }
        -                elsif ($value eq 'under type')
        -                    {  $constant = ::ENUM_UNDER_TYPE();  }
        -                elsif ($value eq 'under parent')
        -                    {  $constant = ::ENUM_UNDER_PARENT();  };
        -
        -                if (defined $constant)
        -                    {  $language->SetEnumValues($constant);  }
        -                else
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('Enum Values must be "Global", "Under Type", or "Under Parent".', $lineNumber);
        -                    };
        -                };
        -            }
        -
        -        else
        -            {
        -            NaturalDocs::ConfigFile->AddError($keyword . ' is not a valid keyword.', $lineNumber);
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: Save
        -#
        -#   Saves the main and user versions of <Languages.txt>.
        -#
        -sub Save
        -    {
        -    my $self = shift;
        -
        -    $self->SaveFile(1); # Main
        -    $self->SaveFile(0); # User
        -    };
        -
        -
        -#
        -#   Function: SaveFile
        -#
        -#   Saves a particular version of <Topics.txt>.
        -#
        -#   Parameters:
        -#
        -#       isMain - Whether the file is the main file or not.
        -#
        -sub SaveFile #(isMain)
        -    {
        -    my ($self, $isMain) = @_;
        -
        -    my $file;
        -
        -    if ($isMain)
        -        {
        -        if (NaturalDocs::Project->MainConfigFileStatus('Languages.txt') == ::FILE_SAME())
        -            {  return;  };
        -        $file = NaturalDocs::Project->MainConfigFile('Languages.txt');
        -        }
        -    else
        -        {
        -        # Have to check the main too because this file lists the languages defined there.
        -        if (NaturalDocs::Project->UserConfigFileStatus('Languages.txt') == ::FILE_SAME() &&
        -            NaturalDocs::Project->MainConfigFileStatus('Languages.txt') == ::FILE_SAME())
        -            {  return;  };
        -        $file = NaturalDocs::Project->UserConfigFile('Languages.txt');
        -        };
        -
        -
        -    # Array of segments, with each being groups of three consecutive entries.  The first is the keyword ('language' or
        -    # 'alter language'), the second is the value, and the third is a hashref of all the properties.
        -    # - For properties that can accept a topic type, the property values are hashrefs mapping topic types to the values.
        -    # - For properties that can accept 'add' or 'replace', there is an additional property ending in 'command' that stores it.
        -    # - For properties that can accept both, the 'command' thing is applied to the topic types rather than the properties.
        -    my @segments;
        -
        -    my @ignoredExtensions;
        -
        -    my $currentProperties;
        -    my $version;
        -
        -    if ($version = NaturalDocs::ConfigFile->Open($file))
        -        {
        -        # We can assume the file is valid.
        -
        -        while (my ($keyword, $value, $comment) = NaturalDocs::ConfigFile->GetLine())
        -            {
        -            $value .= $comment;
        -            $value =~ s/^ //;
        -
        -            if ($keyword eq 'language')
        -                {
        -                $currentProperties = { };
        -
        -                # Case is important with these two.
        -                if (lc($value) eq 'shebang script')
        -                    {  $value = 'Shebang Script';  }
        -                elsif (lc($value) eq 'text file')
        -                    {  $value = 'Text File';  };
        -
        -                push @segments, 'language', $value, $currentProperties;
        -                }
        -
        -            elsif ($keyword eq 'alter language')
        -                {
        -                $currentProperties = { };
        -                push @segments, 'alter language', $languages{lc($value)}->Name(), $currentProperties;
        -                }
        -
        -            elsif ($keyword =~ /^ignored? extensions?$/)
        -                {
        -                $value =~ tr/*.//d;
        -                push @ignoredExtensions, split(/ /, $value);
        -                }
        -
        -            elsif ($keyword eq 'package separator' || $keyword eq 'full language support' || $keyword eq 'perl package' ||
        -                    $keyword eq 'line extender' || $keyword eq 'enum values')
        -                {
        -                $currentProperties->{$keyword} = $value;
        -                }
        -
        -            elsif ($keyword =~ /^line comments?$/)
        -                {
        -                $currentProperties->{'line comments'} = $value;
        -                }
        -            elsif ($keyword =~ /^block comments?$/)
        -                {
        -                $currentProperties->{'block comments'} = $value;
        -                }
        -
        -            elsif ($keyword =~ /^(?:(add|replace) )?extensions?$/)
        -                {
        -                my $command = $1;
        -
        -                if ($command eq 'add' && exists $currentProperties->{'extensions'})
        -                    {  $currentProperties->{'extensions'} .= ' ' . $value;  }
        -                else
        -                    {
        -                    $currentProperties->{'extensions'} = $value;
        -                    $currentProperties->{'extensions command'} = $command;
        -                    };
        -                }
        -
        -            elsif ($keyword =~ /^(?:(add|replace) )?shebang strings?$/)
        -                {
        -                my $command = $1;
        -
        -                if ($command eq 'add' && exists $currentProperties->{'shebang strings'})
        -                    {  $currentProperties->{'shebang strings'} .= ' ' . $value;  }
        -                else
        -                    {
        -                    $currentProperties->{'shebang strings'} = $value;
        -                    $currentProperties->{'shebang strings command'} = $command;
        -                    };
        -                }
        -
        -            elsif ($keyword =~ /^(?:(.+) )?prototype enders?$/)
        -                {
        -                my $topicName = $1;
        -                my $topicType;
        -
        -                if ($topicName)
        -                    {  ($topicType, undef) = NaturalDocs::Topics->NameInfo($topicName);  }
        -                else
        -                    {  $topicType = ::TOPIC_GENERAL();  };
        -
        -                my $currentTypeProperties = $currentProperties->{'prototype enders'};
        -
        -                if (!defined $currentTypeProperties)
        -                    {
        -                    $currentTypeProperties = { };
        -                    $currentProperties->{'prototype enders'} = $currentTypeProperties;
        -                    };
        -
        -                $currentTypeProperties->{$topicType} = $value;
        -                }
        -
        -            elsif ($keyword =~ /^(?:(add|replace) )?ignored? (?:(.+) )?prefix(?:es)? in index$/)
        -                {
        -                my ($command, $topicName) = ($1, $2);
        -                my $topicType;
        -
        -                if ($topicName)
        -                    {  ($topicType, undef) = NaturalDocs::Topics->NameInfo($topicName);  }
        -                else
        -                    {  $topicType = ::TOPIC_GENERAL();  };
        -
        -                my $currentTypeProperties = $currentProperties->{'ignored prefixes in index'};
        -
        -                if (!defined $currentTypeProperties)
        -                    {
        -                    $currentTypeProperties = { };
        -                    $currentProperties->{'ignored prefixes in index'} = $currentTypeProperties;
        -                    };
        -
        -                if ($command eq 'add' && exists $currentTypeProperties->{$topicType})
        -                    {  $currentTypeProperties->{$topicType} .= ' ' . $value;  }
        -                else
        -                    {
        -                    $currentTypeProperties->{$topicType} = $value;
        -                    $currentTypeProperties->{$topicType . ' command'} = $command;
        -                    };
        -                };
        -            };
        -
        -        NaturalDocs::ConfigFile->Close();
        -        };
        -
        -
        -    if (!open(FH_LANGUAGES, '>' . $file))
        -        {
        -        # The main file may be on a shared volume or some other place the user doesn't have write access to.  Since this is only to
        -        # reformat the file, we can ignore the failure.
        -        if ($isMain)
        -            {  return;  }
        -        else
        -            {  die "Couldn't save " . $file;  };
        -        };
        -
        -    print FH_LANGUAGES 'Format: ' . NaturalDocs::Settings->TextAppVersion() . "\n\n";
        -
        -    # Remember the 80 character limit.
        -
        -    if ($isMain)
        -        {
        -        print FH_LANGUAGES
        -        "# This is the main Natural Docs languages file.  If you change anything here,\n"
        -        . "# it will apply to EVERY PROJECT you use Natural Docs on.  If you'd like to\n"
        -        . "# change something for just one project, edit the Languages.txt in its project\n"
        -        . "# directory instead.\n";
        -        }
        -    else
        -        {
        -        print FH_LANGUAGES
        -        "# This is the Natural Docs languages file for this project.  If you change\n"
        -        . "# anything here, it will apply to THIS PROJECT ONLY.  If you'd like to change\n"
        -        . "# something for all your projects, edit the Languages.txt in Natural Docs'\n"
        -        . "# Config directory instead.\n\n\n";
        -
        -        if (scalar @ignoredExtensions == 1)
        -            {
        -            print FH_LANGUAGES
        -            'Ignore Extension: ' . $ignoredExtensions[0] . "\n";
        -            }
        -        elsif (scalar @ignoredExtensions)
        -            {
        -            print FH_LANGUAGES
        -            'Ignore Extensions: ' . join(' ', @ignoredExtensions) . "\n";
        -            }
        -        else
        -            {
        -            print FH_LANGUAGES
        -            "# You can prevent certain file extensions from being scanned like this:\n"
        -            . "# Ignore Extensions: [extension] [extension] ...\n"
        -            };
        -        };
        -
        -    print FH_LANGUAGES
        -    "\n\n"
        -    . "#-------------------------------------------------------------------------------\n"
        -    . "# SYNTAX:\n"
        -    . "#\n"
        -    . "# Unlike other Natural Docs configuration files, in this file all comments\n"
        -    . "# MUST be alone on a line.  Some languages deal with the # character, so you\n"
        -    . "# cannot put comments on the same line as content.\n"
        -    . "#\n"
        -    . "# Also, all lists are separated with spaces, not commas, again because some\n"
        -    . "# languages may need to use them.\n"
        -    . "#\n";
        -
        -    if ($isMain)
        -        {
        -        print FH_LANGUAGES
        -        "# Language: [name]\n"
        -        . "#    Defines a new language.  Its name can use any characters.\n"
        -        . "#\n";
        -        }
        -    else
        -        {
        -        print FH_LANGUAGES
        -        "# Language: [name]\n"
        -        . "# Alter Language: [name]\n"
        -        . "#    Defines a new language or alters an existing one.  Its name can use any\n"
        -        . "#    characters.  If any of the properties below have an add/replace form, you\n"
        -        . "#    must use that when using Alter Language.\n"
        -        . "#\n";
        -        };
        -
        -    print FH_LANGUAGES
        -    "#    The language Shebang Script is special.  It's entry is only used for\n"
        -    . "#    extensions, and files with those extensions have their shebang (#!) lines\n"
        -    . "#    read to determine the real language of the file.  Extensionless files are\n"
        -    . "#    always treated this way.\n"
        -    . "#\n"
        -    . "#    The language Text File is also special.  It's treated as one big comment\n"
        -    . "#    so you can put Natural Docs content in them without special symbols.  Also,\n"
        -    . "#    if you don't specify a package separator, ignored prefixes, or enum value\n"
        -    . "#    behavior, it will copy those settings from the language that is used most\n"
        -    . "#    in the source tree.\n"
        -    . "#\n"
        -    . "# Extensions: [extension] [extension] ...\n";
        -
        -    if ($isMain)
        -        {
        -        print FH_LANGUAGES
        -        "#    Defines the file extensions of the language's source files.  You can use *\n"
        -        . "#    to mean any undefined extension.\n"
        -        . "#\n"
        -        . "# Shebang Strings: [string] [string] ...\n"
        -        . "#    Defines a list of strings that can appear in the shebang (#!) line to\n"
        -        . "#    designate that it's part of the language.\n"
        -        . "#\n";
        -        }
        -    else
        -        {
        -        print FH_LANGUAGES
        -        "# [Add/Replace] Extensions: [extension] [extension] ...\n"
        -        . "#    Defines the file extensions of the language's source files.  You can\n"
        -        . "#    redefine extensions found in the main languages file.  You can use * to\n"
        -        . "#    mean any undefined extension.\n"
        -        . "#\n"
        -        . "# Shebang Strings: [string] [string] ...\n"
        -        . "# [Add/Replace] Shebang Strings: [string] [string] ...\n"
        -        . "#    Defines a list of strings that can appear in the shebang (#!) line to\n"
        -        . "#    designate that it's part of the language.  You can redefine strings found\n"
        -        . "#    in the main languages file.\n"
        -        . "#\n";
        -        };
        -
        -    print FH_LANGUAGES
        -    "# Ignore Prefixes in Index: [prefix] [prefix] ...\n"
        -    . (!$isMain ? "# [Add/Replace] Ignored Prefixes in Index: [prefix] [prefix] ...\n#\n" : '')
        -    . "# Ignore [Topic Type] Prefixes in Index: [prefix] [prefix] ...\n"
        -    . (!$isMain ? "# [Add/Replace] Ignored [Topic Type] Prefixes in Index: [prefix] [prefix] ...\n" : '')
        -    . "#    Specifies prefixes that should be ignored when sorting symbols in an\n"
        -    . "#    index.  Can be specified in general or for a specific topic type.\n"
        -    . "#\n"
        -    . "#------------------------------------------------------------------------------\n"
        -    . "# For basic language support only:\n"
        -    . "#\n"
        -    . "# Line Comments: [symbol] [symbol] ...\n"
        -    . "#    Defines a space-separated list of symbols that are used for line comments,\n"
        -    . "#    if any.\n"
        -    . "#\n"
        -    . "# Block Comments: [opening sym] [closing sym] [opening sym] [closing sym] ...\n"
        -    . "#    Defines a space-separated list of symbol pairs that are used for block\n"
        -    . "#    comments, if any.\n"
        -    . "#\n"
        -    . "# Package Separator: [symbol]\n"
        -    . "#    Defines the default package separator symbol.  The default is a dot.\n"
        -    . "#\n"
        -    . "# [Topic Type] Prototype Enders: [symbol] [symbol] ...\n"
        -    . "#    When defined, Natural Docs will attempt to get a prototype from the code\n"
        -    . "#    immediately following the topic type.  It stops when it reaches one of\n"
        -    . "#    these symbols.  Use \\n for line breaks.\n"
        -    . "#\n"
        -    . "# Line Extender: [symbol]\n"
        -    . "#    Defines the symbol that allows a prototype to span multiple lines if\n"
        -    . "#    normally a line break would end it.\n"
        -    . "#\n"
        -    . "# Enum Values: [global|under type|under parent]\n"
        -    . "#    Defines how enum values are referenced.  The default is global.\n"
        -    . "#    global       - Values are always global, referenced as 'value'.\n"
        -    . "#    under type   - Values are under the enum type, referenced as\n"
        -    . "#               'package.enum.value'.\n"
        -    . "#    under parent - Values are under the enum's parent, referenced as\n"
        -    . "#               'package.value'.\n"
        -    . "#\n"
        -    . "# Perl Package: [perl package]\n"
        -    . "#    Specifies the Perl package used to fine-tune the language behavior in ways\n"
        -    . "#    too complex to do in this file.\n"
        -    . "#\n"
        -    . "#------------------------------------------------------------------------------\n"
        -    . "# For full language support only:\n"
        -    . "#\n"
        -    . "# Full Language Support: [perl package]\n"
        -    . "#    Specifies the Perl package that has the parsing routines necessary for full\n"
        -    . "#    language support.\n"
        -    . "#\n"
        -    . "#-------------------------------------------------------------------------------\n\n";
        -
        -    if ($isMain)
        -        {
        -        print FH_LANGUAGES
        -        "# The following languages MUST be defined in this file:\n"
        -        . "#\n"
        -        . "#    Text File, Shebang Script\n";
        -        }
        -    else
        -        {
        -        print FH_LANGUAGES
        -        "# The following languages are defined in the main file, if you'd like to alter\n"
        -        . "# them:\n"
        -        . "#\n"
        -        . Text::Wrap::wrap('#    ', '#    ', join(', ', @mainLanguageNames)) . "\n";
        -        };
        -
        -    print FH_LANGUAGES "\n"
        -    . "# If you add a language that you think would be useful to other developers\n"
        -    . "# and should be included in Natural Docs by default, please e-mail it to\n"
        -    . "# languages [at] naturaldocs [dot] org.\n";
        -
        -    my @topicTypeOrder = ( ::TOPIC_GENERAL(), ::TOPIC_CLASS(), ::TOPIC_FUNCTION(), ::TOPIC_VARIABLE(),
        -                                         ::TOPIC_PROPERTY(), ::TOPIC_TYPE(), ::TOPIC_CONSTANT() );
        -
        -    for (my $i = 0; $i < scalar @segments; $i += 3)
        -        {
        -        my ($keyword, $name, $properties) = @segments[$i..$i+2];
        -
        -        print FH_LANGUAGES "\n\n";
        -
        -        if ($keyword eq 'language')
        -            {  print FH_LANGUAGES 'Language: ' . $name . "\n\n";  }
        -        else
        -            {  print FH_LANGUAGES 'Alter Language: ' . $name . "\n\n";  };
        -
        -        if (exists $properties->{'extensions'})
        -            {
        -            print FH_LANGUAGES '   ';
        -
        -            if ($properties->{'extensions command'})
        -                {  print FH_LANGUAGES ucfirst($properties->{'extensions command'}) . ' ';  };
        -
        -            my @extensions = split(/ /, $properties->{'extensions'}, 2);
        -
        -            if (scalar @extensions == 1)
        -                {  print FH_LANGUAGES 'Extension: ';  }
        -            else
        -                {  print FH_LANGUAGES 'Extensions: ';  };
        -
        -            print FH_LANGUAGES lc($properties->{'extensions'}) . "\n";
        -            };
        -
        -        if (exists $properties->{'shebang strings'})
        -            {
        -            print FH_LANGUAGES '   ';
        -
        -            if ($properties->{'shebang strings command'})
        -                {  print FH_LANGUAGES ucfirst($properties->{'shebang strings command'}) . ' ';  };
        -
        -            my @shebangStrings = split(/ /, $properties->{'shebang strings'}, 2);
        -
        -            if (scalar @shebangStrings == 1)
        -                {  print FH_LANGUAGES 'Shebang String: ';  }
        -            else
        -                {  print FH_LANGUAGES 'Shebang Strings: ';  };
        -
        -            print FH_LANGUAGES lc($properties->{'shebang strings'}) . "\n";
        -            };
        -
        -        if (exists $properties->{'ignored prefixes in index'})
        -            {
        -            my $topicTypePrefixes = $properties->{'ignored prefixes in index'};
        -
        -            my %usedTopicTypes;
        -            my @topicTypes = ( @topicTypeOrder, keys %$topicTypePrefixes );
        -
        -            foreach my $topicType (@topicTypes)
        -                {
        -                if ($topicType !~ / command$/ &&
        -                    exists $topicTypePrefixes->{$topicType} &&
        -                    !exists $usedTopicTypes{$topicType})
        -                    {
        -                    print FH_LANGUAGES '   ';
        -
        -                    if ($topicTypePrefixes->{$topicType . ' command'})
        -                        {  print FH_LANGUAGES ucfirst($topicTypePrefixes->{$topicType . ' command'}) . ' Ignored ';  }
        -                    else
        -                        {  print FH_LANGUAGES 'Ignore ';  };
        -
        -                    if ($topicType ne ::TOPIC_GENERAL())
        -                        {  print FH_LANGUAGES NaturalDocs::Topics->TypeInfo($topicType)->Name() . ' ';  };
        -
        -                    my @prefixes = split(/ /, $topicTypePrefixes->{$topicType}, 2);
        -
        -                    if (scalar @prefixes == 1)
        -                        {  print FH_LANGUAGES 'Prefix in Index: ';  }
        -                    else
        -                        {  print FH_LANGUAGES 'Prefixes in Index: ';  };
        -
        -                    print FH_LANGUAGES $topicTypePrefixes->{$topicType} . "\n";
        -
        -                    $usedTopicTypes{$topicType} = 1;
        -                    };
        -                };
        -            };
        -
        -        if (exists $properties->{'line comments'})
        -            {
        -            my @comments = split(/ /, $properties->{'line comments'}, 2);
        -
        -            if (scalar @comments == 1)
        -                {  print FH_LANGUAGES '   Line Comment: ';  }
        -            else
        -                {  print FH_LANGUAGES '   Line Comments: ';  };
        -
        -            print FH_LANGUAGES $properties->{'line comments'} . "\n";
        -            };
        -
        -        if (exists $properties->{'block comments'})
        -            {
        -            my @comments = split(/ /, $properties->{'block comments'}, 3);
        -
        -            if (scalar @comments == 2)
        -                {  print FH_LANGUAGES '   Block Comment: ';  }
        -            else
        -                {  print FH_LANGUAGES '   Block Comments: ';  };
        -
        -            print FH_LANGUAGES $properties->{'block comments'} . "\n";
        -            };
        -
        -        if (exists $properties->{'package separator'})
        -            {
        -            # Prior to 1.32, Package Separator was allowed for full language support.  Ignore it when reformatting.
        -            if ($version >= NaturalDocs::Version->FromString('1.32') || !exists $properties->{'full language support'})
        -                {  print FH_LANGUAGES '   Package Separator: ' . $properties->{'package separator'} . "\n";  };
        -            };
        -
        -        if (exists $properties->{'enum values'})
        -            {
        -            print FH_LANGUAGES '   Enum Values: ' . ucfirst(lc($properties->{'enum values'})) . "\n";
        -            };
        -
        -        if (exists $properties->{'prototype enders'})
        -            {
        -            my $topicTypeEnders = $properties->{'prototype enders'};
        -
        -            my %usedTopicTypes;
        -            my @topicTypes = ( @topicTypeOrder, keys %$topicTypeEnders );
        -
        -            foreach my $topicType (@topicTypes)
        -                {
        -                if ($topicType !~ / command$/ &&
        -                    exists $topicTypeEnders->{$topicType} &&
        -                    !exists $usedTopicTypes{$topicType})
        -                    {
        -                    print FH_LANGUAGES '   ';
        -
        -                    if ($topicType ne ::TOPIC_GENERAL())
        -                        {  print FH_LANGUAGES NaturalDocs::Topics->TypeInfo($topicType)->Name() . ' ';  };
        -
        -                    my @enders = split(/ /, $topicTypeEnders->{$topicType}, 2);
        -
        -                    if (scalar @enders == 1)
        -                        {  print FH_LANGUAGES 'Prototype Ender: ';  }
        -                    else
        -                        {  print FH_LANGUAGES 'Prototype Enders: ';  };
        -
        -                    print FH_LANGUAGES $topicTypeEnders->{$topicType} . "\n";
        -
        -                    $usedTopicTypes{$topicType} = 1;
        -                    };
        -                };
        -            };
        -
        -        if (exists $properties->{'line extender'})
        -            {
        -            print FH_LANGUAGES '   Line Extender: ' . $properties->{'line extender'} . "\n";
        -            };
        -
        -        if (exists $properties->{'perl package'})
        -            {
        -            print FH_LANGUAGES '   Perl Package: ' . $properties->{'perl package'} . "\n";
        -            };
        -
        -        if (exists $properties->{'full language support'})
        -            {
        -            print FH_LANGUAGES '   Full Language Support: ' . $properties->{'full language support'} . "\n";
        -            };
        -        };
        -
        -    close(FH_LANGUAGES);
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Functions
        -
        -
        -#
        -#   Function: LanguageOf
        -#
        -#   Returns the language of the passed source file.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The source <FileName> to get the language of.
        -#
        -#   Returns:
        -#
        -#       A <NaturalDocs::Languages::Base>-derived object for the passed file, or undef if the file is not a recognized language.
        -#
        -sub LanguageOf #(sourceFile)
        -    {
        -    my ($self, $sourceFile) = @_;
        -
        -    my $extension = NaturalDocs::File->ExtensionOf($sourceFile);
        -    if (defined $extension)
        -        {  $extension = lc($extension);  };
        -
        -    my $languageName;
        -
        -    if (!defined $extension)
        -        {  $languageName = 'shebang script';  }
        -    else
        -        {  $languageName = $extensions{$extension};  };
        -
        -    if (!defined $languageName)
        -        {  $languageName = $extensions{'*'};  };
        -
        -    if (defined $languageName)
        -        {
        -        if ($languageName eq 'shebang script')
        -            {
        -            if (exists $shebangFiles{$sourceFile})
        -                {
        -                if (defined $shebangFiles{$sourceFile})
        -                    {  return $languages{$shebangFiles{$sourceFile}};  }
        -                else
        -                    {  return undef;  };
        -                }
        -
        -            else # (!exists $shebangFiles{$sourceFile})
        -                {
        -                my $shebangLine;
        -
        -                if (open(SOURCEFILEHANDLE, '<' . $sourceFile))
        -                	{
        -                    my $lineReader = NaturalDocs::LineReader->New(\*SOURCEFILEHANDLE);
        -                    $shebangLine = $lineReader->Get();
        -
        -	                if (substr($shebangLine, 0, 2) ne '#!')
        -	                    {  $shebangLine = undef;  };
        -
        -	                close (SOURCEFILEHANDLE);
        -	                }
        -	            elsif (defined $extension)
        -	            	{  die 'Could not open ' . $sourceFile;  }
        -	            # Ignore extensionless files that can't be opened.  They may be system files.
        -
        -                if (!defined $shebangLine)
        -                    {
        -                    $shebangFiles{$sourceFile} = undef;
        -                    return undef;
        -                    }
        -                else
        -                    {
        -                    $shebangLine = lc($shebangLine);
        -
        -                    foreach my $shebangString (keys %shebangStrings)
        -                        {
        -                        if (index($shebangLine, $shebangString) != -1)
        -                            {
        -                            $shebangFiles{$sourceFile} = $shebangStrings{$shebangString};
        -                            return $languages{$shebangStrings{$shebangString}};
        -                            };
        -                        };
        -
        -                    $shebangFiles{$sourceFile} = undef;
        -                    return undef;
        -                    };
        -                };
        -            }
        -
        -        else # language name ne 'shebang script'
        -            {  return $languages{$languageName};  };
        -        }
        -    else # !defined $language
        -        {
        -        return undef;
        -        };
        -    };
        -
        -
        -#
        -#   Function: OnMostUsedLanguageKnown
        -#
        -#   Called when the most used language is known.
        -#
        -sub OnMostUsedLanguageKnown
        -    {
        -    my $self = shift;
        -
        -    my $language = $languages{lc( NaturalDocs::Project->MostUsedLanguage() )};
        -
        -    if ($language)
        -        {
        -        if (!$languages{'text file'}->HasIgnoredPrefixes())
        -            {  $languages{'text file'}->CopyIgnoredPrefixesOf($language);  };
        -        if (!$languages{'text file'}->PackageSeparatorWasSet())
        -            {  $languages{'text file'}->SetPackageSeparator($language->PackageSeparator());  };
        -        if (!$languages{'text file'}->EnumValuesWasSet())
        -            {  $languages{'text file'}->SetEnumValues($language->EnumValues());  };
        -        };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages/ActionScript.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages/ActionScript.pm
        deleted file mode 100644
        index b24ba9d6e..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages/ActionScript.pm
        +++ /dev/null
        @@ -1,1487 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Languages::ActionScript
        -#
        -###############################################################################
        -#
        -#   A subclass to handle the language variations of Flash ActionScript.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Languages::ActionScript;
        -
        -use base 'NaturalDocs::Languages::Advanced';
        -
        -
        -################################################################################
        -# Group: Constants and Types
        -
        -
        -#
        -#   Constants: XML Tag Type
        -#
        -#   XML_OPENING_TAG - The tag is an opening one, such as <tag>.
        -#   XML_CLOSING_TAG - The tag is a closing one, such as </tag>.
        -#   XML_SELF_CONTAINED_TAG - The tag is self contained, such as <tag />.
        -#
        -use constant XML_OPENING_TAG => 1;
        -use constant XML_CLOSING_TAG => 2;
        -use constant XML_SELF_CONTAINED_TAG => 3;
        -
        -
        -################################################################################
        -# Group: Package Variables
        -
        -#
        -#   hash: classModifiers
        -#   An existence hash of all the acceptable class modifiers.  The keys are in all lowercase.
        -#
        -my %classModifiers = ( 'dynamic' => 1,
        -                                   'intrinsic' => 1,
        -                                   'final' => 1,
        -                                   'internal' => 1,
        -                                   'public' => 1 );
        -
        -#
        -#   hash: memberModifiers
        -#   An existence hash of all the acceptable class member modifiers.  The keys are in all lowercase.
        -#
        -my %memberModifiers = ( 'public' => 1,
        -                                        'private' => 1,
        -                                        'protected' => 1,
        -                                        'static' => 1,
        -                                        'internal' => 1,
        -                                        'override' => 1 );
        -
        -
        -#
        -#   hash: declarationEnders
        -#   An existence hash of all the tokens that can end a declaration.  This is important because statements don't require a semicolon
        -#   to end.  The keys are in all lowercase.
        -#
        -my %declarationEnders = ( ';' => 1,
        -                                        '}' => 1,
        -                                        '{' => 1,
        -                                        'public' => 1,
        -                                        'private' => 1,
        -                                        'protected' => 1,
        -                                        'static' => 1,
        -                                        'internal' => 1,
        -                                        'dynamic' => 1,
        -                                        'intrinsic' => 1,
        -                                        'final' => 1,
        -                                        'override' => 1,
        -                                        'class' => 1,
        -                                        'interface' => 1,
        -                                        'var' => 1,
        -                                        'function' => 1,
        -                                        'const' => 1,
        -                                        'namespace' => 1,
        -                                        'import' => 1 );
        -
        -
        -#
        -#   var: isEscaped
        -#   Whether the current file being parsed uses escapement.
        -#
        -my $isEscaped;
        -
        -
        -
        -################################################################################
        -# Group: Interface Functions
        -
        -
        -#
        -#   Function: PackageSeparator
        -#   Returns the package separator symbol.
        -#
        -sub PackageSeparator
        -    {  return '.';  };
        -
        -
        -#
        -#   Function: EnumValues
        -#   Returns the <EnumValuesType> that describes how the language handles enums.
        -#
        -sub EnumValues
        -    {  return ::ENUM_GLOBAL();  };
        -
        -
        -#
        -#   Function: ParseParameterLine
        -#   Parses a prototype parameter line and returns it as a <NaturalDocs::Languages::Prototype::Parameter> object.
        -#
        -sub ParseParameterLine #(line)
        -    {
        -    my ($self, $line) = @_;
        -
        -    if ($line =~ /^ ?\.\.\.\ (.+)$/)
        -        {
        -        # This puts them in the wrong fields as $1 should be the name and ... should be the type.  However, this is necessary
        -        # because the order in the source is reversed from other parameter declarations and it's more important for the output
        -        # to match the source.
        -        return NaturalDocs::Languages::Prototype::Parameter->New($1, undef, '...', undef, undef, undef);
        -        }
        -    else
        -        {  return $self->ParsePascalParameterLine($line);  };
        -    };
        -
        -
        -#
        -#   Function: TypeBeforeParameter
        -#   Returns whether the type appears before the parameter in prototypes.
        -#
        -sub TypeBeforeParameter
        -    {  return 0;  };
        -
        -
        -#
        -#   Function: PreprocessFile
        -#
        -#   If the file is escaped, strips out all unescaped code.  Will translate any unescaped comments into comments surrounded by
        -#   "\x1C\x1D\x1E\x1F" and "\x1F\x1E\x1D" characters, so chosen because they are the same character lengths as <!-- and -->
        -#   and will not appear in normal code.
        -#
        -sub PreprocessFile
        -    {
        -    my ($self, $lines) = @_;
        -
        -    if (!$isEscaped)
        -        {  return;  };
        -
        -    use constant MODE_UNESCAPED_REGULAR => 1;
        -    use constant MODE_UNESCAPED_PI => 2;
        -    use constant MODE_UNESCAPED_CDATA => 3;
        -    use constant MODE_UNESCAPED_COMMENT => 4;
        -    use constant MODE_ESCAPED_UNKNOWN_CDATA => 5;
        -    use constant MODE_ESCAPED_CDATA => 6;
        -    use constant MODE_ESCAPED_NO_CDATA => 7;
        -
        -    my $mode = MODE_UNESCAPED_REGULAR;
        -
        -    for (my $i = 0; $i < scalar @$lines; $i++)
        -        {
        -        my @tokens = split(/(<[ \t]*\/?[ \t]*mx:Script[^>]*>|<\?|\?>|<\!--|-->|<\!\[CDATA\[|\]\]\>)/, $lines->[$i]);
        -        my $newLine;
        -
        -        foreach my $token (@tokens)
        -            {
        -            if ($mode == MODE_UNESCAPED_REGULAR)
        -                {
        -                if ($token eq '<?')
        -                    {  $mode = MODE_UNESCAPED_PI;  }
        -                elsif ($token eq '<![CDATA[')
        -                    {  $mode = MODE_UNESCAPED_CDATA;  }
        -                elsif ($token eq '<!--')
        -                    {
        -                    $mode = MODE_UNESCAPED_COMMENT;
        -                    $newLine .= "\x1C\x1D\x1E\x1F";
        -                    }
        -                elsif ($token =~ /^<[ \t]*mx:Script/)
        -                    {  $mode = MODE_ESCAPED_UNKNOWN_CDATA;  };
        -                }
        -
        -            elsif ($mode == MODE_UNESCAPED_PI)
        -                {
        -                if ($token eq '?>')
        -                    {  $mode = MODE_UNESCAPED_REGULAR;  };
        -                }
        -
        -            elsif ($mode == MODE_UNESCAPED_CDATA)
        -                {
        -                if ($token eq ']]>')
        -                    {  $mode = MODE_UNESCAPED_REGULAR;  };
        -                }
        -
        -            elsif ($mode == MODE_UNESCAPED_COMMENT)
        -                {
        -                if ($token eq '-->')
        -                    {
        -                    $mode = MODE_UNESCAPED_REGULAR;
        -                    $newLine .= "\x1F\x1E\x1D";
        -                    }
        -                else
        -                    {  $newLine .= $token;  };
        -                }
        -
        -            elsif ($mode == MODE_ESCAPED_UNKNOWN_CDATA)
        -                {
        -                if ($token eq '<![CDATA[')
        -                    {  $mode = MODE_ESCAPED_CDATA;  }
        -                elsif ($token =~ /^<[ \t]*\/[ \t]*mx:Script/)
        -                    {
        -                    $mode = MODE_UNESCAPED_REGULAR;
        -                    $newLine .= '; ';
        -                    }
        -                elsif ($token !~ /^[ \t]*$/)
        -                    {
        -                    $mode = MODE_ESCAPED_NO_CDATA;
        -                    $newLine .= $token;
        -                    };
        -                }
        -
        -            elsif ($mode == MODE_ESCAPED_CDATA)
        -                {
        -                if ($token eq ']]>')
        -                    {
        -                    $mode = MODE_UNESCAPED_REGULAR;
        -                    $newLine .= '; ';
        -                    }
        -                else
        -                    {  $newLine .= $token;  };
        -                }
        -
        -            else #($mode == MODE_ESCAPED_NO_CDATA)
        -                {
        -                if ($token =~ /^<[ \t]*\/[ \t]*mx:Script/)
        -                    {
        -                    $mode = MODE_UNESCAPED_REGULAR;
        -                    $newLine .= '; ';
        -                    }
        -                else
        -                    {  $newLine .= $token;  };
        -                };
        -
        -            };
        -
        -        $lines->[$i] = $newLine;
        -        };
        -    };
        -
        -
        -#
        -#   Function: ParseFile
        -#
        -#   Parses the passed source file, sending comments acceptable for documentation to <NaturalDocs::Parser->OnComment()>.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The <FileName> to parse.
        -#       topicList - A reference to the list of <NaturalDocs::Parser::ParsedTopics> being built by the file.
        -#
        -#   Returns:
        -#
        -#       The array ( autoTopics, scopeRecord ).
        -#
        -#       autoTopics - An arrayref of automatically generated topics from the file, or undef if none.
        -#       scopeRecord - An arrayref of <NaturalDocs::Languages::Advanced::ScopeChanges>, or undef if none.
        -#
        -sub ParseFile #(sourceFile, topicsList)
        -    {
        -    my ($self, $sourceFile, $topicsList) = @_;
        -
        -    # The \x1# comment symbols are inserted by PreprocessFile() to stand in for XML comments in escaped files.
        -    my @parseParameters = ( [ '//' ], [ '/*', '*/', "\x1C\x1D\x1E\x1F", "\x1F\x1E\x1D" ], [ '///' ], [ '/**', '*/' ] );
        -
        -    my $extension = lc(NaturalDocs::File->ExtensionOf($sourceFile));
        -    $isEscaped = ($extension eq 'mxml');
        -
        -    $self->ParseForCommentsAndTokens($sourceFile, @parseParameters);
        -
        -    my $tokens = $self->Tokens();
        -    my $index = 0;
        -    my $lineNumber = 1;
        -
        -    while ($index < scalar @$tokens)
        -        {
        -        if ($self->TryToSkipWhitespace(\$index, \$lineNumber) ||
        -            $self->TryToGetImport(\$index, \$lineNumber) ||
        -            $self->TryToGetClass(\$index, \$lineNumber) ||
        -            $self->TryToGetFunction(\$index, \$lineNumber) ||
        -            $self->TryToGetVariable(\$index, \$lineNumber) )
        -            {
        -            # The functions above will handle everything.
        -            }
        -
        -        elsif ($tokens->[$index] eq '{')
        -            {
        -            $self->StartScope('}', $lineNumber, undef, undef, undef);
        -            $index++;
        -            }
        -
        -        elsif ($tokens->[$index] eq '}')
        -            {
        -            if ($self->ClosingScopeSymbol() eq '}')
        -                {  $self->EndScope($lineNumber);  };
        -
        -            $index++;
        -            }
        -
        -        else
        -            {
        -            $self->SkipToNextStatement(\$index, \$lineNumber);
        -            };
        -        };
        -
        -
        -    # Don't need to keep these around.
        -    $self->ClearTokens();
        -
        -
        -    my $autoTopics = $self->AutoTopics();
        -
        -    my $scopeRecord = $self->ScopeRecord();
        -    if (defined $scopeRecord && !scalar @$scopeRecord)
        -        {  $scopeRecord = undef;  };
        -
        -    return ( $autoTopics, $scopeRecord );
        -    };
        -
        -
        -
        -################################################################################
        -# Group: Statement Parsing Functions
        -# All functions here assume that the current position is at the beginning of a statement.
        -#
        -# Note for developers: I am well aware that the code in these functions do not check if we're past the end of the tokens as
        -# often as it should.  We're making use of the fact that Perl will always return undef in these cases to keep the code simpler.
        -
        -
        -#
        -#   Function: TryToGetIdentifier
        -#
        -#   Determines whether the position is at an identifier, and if so, skips it and returns the complete identifier as a string.  Returns
        -#   undef otherwise.
        -#
        -#   Parameters:
        -#
        -#       indexRef - A reference to the current token index.
        -#       lineNumberRef - A reference to the current line number.
        -#       allowStar - If set, allows the last identifier to be a star.
        -#
        -sub TryToGetIdentifier #(indexRef, lineNumberRef, allowStar)
        -    {
        -    my ($self, $indexRef, $lineNumberRef, $allowStar) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $index = $$indexRef;
        -
        -    use constant MODE_IDENTIFIER_START => 1;
        -    use constant MODE_IN_IDENTIFIER => 2;
        -    use constant MODE_AFTER_STAR => 3;
        -
        -    my $identifier;
        -    my $mode = MODE_IDENTIFIER_START;
        -
        -    while ($index < scalar @$tokens)
        -        {
        -        if ($mode == MODE_IDENTIFIER_START)
        -            {
        -            if ($tokens->[$index] =~ /^[a-z\$\_]/i)
        -                {
        -                $identifier .= $tokens->[$index];
        -                $index++;
        -
        -                $mode = MODE_IN_IDENTIFIER;
        -                }
        -            elsif ($allowStar && $tokens->[$index] eq '*')
        -                {
        -                $identifier .= '*';
        -                $index++;
        -
        -                $mode = MODE_AFTER_STAR;
        -                }
        -            else
        -                {  return undef;  };
        -            }
        -
        -        elsif ($mode == MODE_IN_IDENTIFIER)
        -            {
        -            if ($tokens->[$index] eq '.')
        -                {
        -                $identifier .= '.';
        -                $index++;
        -
        -                $mode = MODE_IDENTIFIER_START;
        -                }
        -            elsif ($tokens->[$index] =~ /^[a-z0-9\$\_]/i)
        -                {
        -                $identifier .= $tokens->[$index];
        -                $index++;
        -                }
        -            else
        -                {  last;  };
        -            }
        -
        -        else #($mode == MODE_AFTER_STAR)
        -            {
        -            if ($tokens->[$index] =~ /^[a-z0-9\$\_\.]/i)
        -                {  return undef;  }
        -            else
        -                {  last;  };
        -            };
        -        };
        -
        -    # We need to check again because we may have run out of tokens after a dot.
        -    if ($mode != MODE_IDENTIFIER_START)
        -        {
        -        $$indexRef = $index;
        -        return $identifier;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: TryToGetImport
        -#
        -#   Determines whether the position is at a import statement, and if so, adds it as a Using statement to the current scope, skips
        -#   it, and returns true.
        -#
        -sub TryToGetImport #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $index = $$indexRef;
        -    my $lineNumber = $$lineNumberRef;
        -
        -    if ($tokens->[$index] ne 'import')
        -        {  return undef;  };
        -
        -    $index++;
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -    my $identifier = $self->TryToGetIdentifier(\$index, \$lineNumber, 1);
        -    if (!$identifier)
        -        {  return undef;  };
        -
        -
        -    # Currently we implement importing by stripping the last package level and treating it as a using.  So "import p1.p2.p3" makes
        -    # p1.p2 the using path, which is over-tolerant but that's okay.  "import p1.p2.*" is treated the same way, but in this case it's
        -    # not over-tolerant.  If there's no dot, there's no point to including it.
        -
        -    if (index($identifier, '.') != -1)
        -        {
        -        $identifier =~ s/\.[^\.]+$//;
        -        $self->AddUsing( NaturalDocs::SymbolString->FromText($identifier) );
        -        };
        -
        -    $$indexRef = $index;
        -    $$lineNumberRef = $lineNumber;
        -
        -    return 1;
        -    };
        -
        -
        -#
        -#   Function: TryToGetClass
        -#
        -#   Determines whether the position is at a class declaration statement, and if so, generates a topic for it, skips it, and
        -#   returns true.
        -#
        -#   Supported Syntaxes:
        -#
        -#       - Classes
        -#       - Interfaces
        -#       - Classes and interfaces with _global
        -#
        -sub TryToGetClass #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $index = $$indexRef;
        -    my $lineNumber = $$lineNumberRef;
        -
        -    my @modifiers;
        -
        -    while ($tokens->[$index] =~ /^[a-z]/i &&
        -              exists $classModifiers{lc($tokens->[$index])} )
        -        {
        -        push @modifiers, lc($tokens->[$index]);
        -        $index++;
        -
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        };
        -
        -    my $type;
        -
        -    if ($tokens->[$index] eq 'class' || $tokens->[$index] eq 'interface')
        -        {
        -        $type = $tokens->[$index];
        -
        -        $index++;
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        }
        -    else
        -        {  return undef;  };
        -
        -    my $className = $self->TryToGetIdentifier(\$index, \$lineNumber);
        -
        -    if (!$className)
        -        {  return undef;  };
        -
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -    my @parents;
        -
        -    if ($tokens->[$index] eq 'extends')
        -        {
        -        $index++;
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        # Interfaces can extend multiple other interfaces, which is NOT clearly mentioned in the docs.
        -
        -        for (;;)
        -        	{
        -	        my $parent = $self->TryToGetIdentifier(\$index, \$lineNumber);
        -	        if (!$parent)
        -	            {  return undef;  };
        -
        -	        push @parents, $parent;
        -
        -	        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -            if ($tokens->[$index] ne ',')
        -                {  last;  }
        -            else
        -                {
        -                $index++;
        -                $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -                };
        -	        }
        -        };
        -
        -    if ($type eq 'class' && $tokens->[$index] eq 'implements')
        -        {
        -        $index++;
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        for (;;)
        -            {
        -            my $parent = $self->TryToGetIdentifier(\$index, \$lineNumber);
        -            if (!$parent)
        -                {  return undef;  };
        -
        -            push @parents, $parent;
        -
        -            $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -            if ($tokens->[$index] ne ',')
        -                {  last;  }
        -            else
        -                {
        -                $index++;
        -                $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -                };
        -            };
        -        };
        -
        -    if ($tokens->[$index] ne '{')
        -        {  return undef;  };
        -
        -    $index++;
        -
        -
        -    # If we made it this far, we have a valid class declaration.
        -
        -    my $topicType;
        -
        -    if ($type eq 'interface')
        -        {  $topicType = ::TOPIC_INTERFACE();  }
        -    else
        -        {  $topicType = ::TOPIC_CLASS();  };
        -
        -    $className =~ s/^_global.//;
        -
        -    my $autoTopic = NaturalDocs::Parser::ParsedTopic->New($topicType, $className,
        -                                                                                         undef, $self->CurrentUsing(),
        -                                                                                         undef,
        -                                                                                         undef, undef, $$lineNumberRef);
        -
        -    $self->AddAutoTopic($autoTopic);
        -    NaturalDocs::Parser->OnClass($autoTopic->Package());
        -
        -    foreach my $parent (@parents)
        -        {
        -        NaturalDocs::Parser->OnClassParent($autoTopic->Package(), NaturalDocs::SymbolString->FromText($parent),
        -                                                               undef, $self->CurrentUsing(), ::RESOLVE_ABSOLUTE());
        -        };
        -
        -    $self->StartScope('}', $lineNumber, $autoTopic->Package());
        -
        -    $$indexRef = $index;
        -    $$lineNumberRef = $lineNumber;
        -
        -    return 1;
        -    };
        -
        -
        -#
        -#   Function: TryToGetFunction
        -#
        -#   Determines if the position is on a function declaration, and if so, generates a topic for it, skips it, and returns true.
        -#
        -#   Supported Syntaxes:
        -#
        -#       - Functions
        -#       - Constructors
        -#       - Properties
        -#       - Functions with _global
        -#       - Functions with namespaces
        -#
        -sub TryToGetFunction #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $index = $$indexRef;
        -    my $lineNumber = $$lineNumberRef;
        -
        -    my $startIndex = $index;
        -    my $startLine = $lineNumber;
        -
        -    my @modifiers;
        -    my $namespace;
        -
        -    while ($tokens->[$index] =~ /^[a-z]/i)
        -        {
        -        if ($tokens->[$index] eq 'function')
        -            {  last;  }
        -
        -        elsif (exists $memberModifiers{lc($tokens->[$index])})
        -            {
        -            push @modifiers, lc($tokens->[$index]);
        -            $index++;
        -
        -            $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -            }
        -
        -        elsif (!$namespace)
        -            {
        -            do
        -                {
        -                $namespace .= $tokens->[$index];
        -                $index++;
        -                }
        -            while ($tokens->[$index] =~ /^[a-z0-9_]/i);
        -
        -            $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -            }
        -
        -        else
        -            {  last;  };
        -        };
        -
        -    if ($tokens->[$index] ne 'function')
        -        {  return undef;  };
        -    $index++;
        -
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -    my $type;
        -
        -    if ($tokens->[$index] eq 'get' || $tokens->[$index] eq 'set')
        -        {
        -        # This can either be a property ("function get Something()") or a function name ("function get()").
        -
        -        my $nextIndex = $index;
        -        my $nextLineNumber = $lineNumber;
        -
        -        $nextIndex++;
        -        $self->TryToSkipWhitespace(\$nextIndex, \$nextLineNumber);
        -
        -        if ($tokens->[$nextIndex] eq '(')
        -            {
        -            $type = ::TOPIC_FUNCTION();
        -            # Ignore the movement and let the code ahead pick it up as the name.
        -            }
        -        else
        -            {
        -            $type = ::TOPIC_PROPERTY();
        -            $index = $nextIndex;
        -            $lineNumber = $nextLineNumber;
        -            };
        -        }
        -    else
        -        {  $type = ::TOPIC_FUNCTION();  };
        -
        -    my $name = $self->TryToGetIdentifier(\$index, \$lineNumber);
        -    if (!$name)
        -        {  return undef;  };
        -
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -    if ($tokens->[$index] ne '(')
        -        {  return undef;  };
        -
        -    $index++;
        -    $self->GenericSkipUntilAfter(\$index, \$lineNumber, ')');
        -
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -    if ($tokens->[$index] eq ':')
        -        {
        -        $index++;
        -
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        $self->TryToGetIdentifier(\$index, \$lineNumber, 1);
        -
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        };
        -
        -
        -    my $prototype = $self->NormalizePrototype( $self->CreateString($startIndex, $index) );
        -
        -    if ($tokens->[$index] eq '{')
        -        {  $self->GenericSkip(\$index, \$lineNumber);  }
        -    elsif (!exists $declarationEnders{$tokens->[$index]})
        -        {  return undef;  };
        -
        -
        -    my $scope = $self->CurrentScope();
        -
        -    if ($name =~ s/^_global.//)
        -        {  $scope = undef;  };
        -    if ($namespace)
        -        {  $scope = NaturalDocs::SymbolString->Join($scope, $namespace);  };
        -
        -    $self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New($type, $name,
        -                                                                                              $scope, $self->CurrentUsing(),
        -                                                                                              $prototype,
        -                                                                                              undef, undef, $startLine));
        -
        -
        -    # We succeeded if we got this far.
        -
        -    $$indexRef = $index;
        -    $$lineNumberRef = $lineNumber;
        -
        -    return 1;
        -    };
        -
        -
        -#
        -#   Function: TryToGetVariable
        -#
        -#   Determines if the position is on a variable declaration statement, and if so, generates a topic for each variable, skips the
        -#   statement, and returns true.
        -#
        -#   Supported Syntaxes:
        -#
        -#       - Variables
        -#       - Variables with _global
        -#       - Variables with type * (untyped)
        -#       - Constants
        -#       - Variables and constants with namespaces
        -#
        -sub TryToGetVariable #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $index = $$indexRef;
        -    my $lineNumber = $$lineNumberRef;
        -
        -    my $startIndex = $index;
        -    my $startLine = $lineNumber;
        -
        -    my @modifiers;
        -    my $namespace;
        -
        -    while ($tokens->[$index] =~ /^[a-z]/i)
        -        {
        -        if ($tokens->[$index] eq 'var' || $tokens->[$index] eq 'const')
        -            {  last;  }
        -
        -        elsif (exists $memberModifiers{lc($tokens->[$index])})
        -            {
        -            push @modifiers, lc($tokens->[$index]);
        -            $index++;
        -
        -            $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -            }
        -
        -        elsif (!$namespace)
        -            {
        -            do
        -                {
        -                $namespace .= $tokens->[$index];
        -                $index++;
        -                }
        -            while ($tokens->[$index] =~ /^[a-z0-9_]/i);
        -
        -            $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -            }
        -
        -        else
        -            {  last;  };
        -        };
        -
        -    my $type;
        -
        -    if ($tokens->[$index] eq 'var')
        -        {  $type = ::TOPIC_VARIABLE();  }
        -    elsif ($tokens->[$index] eq 'const')
        -        {  $type = ::TOPIC_CONSTANT();  }
        -    else
        -        {  return undef;  };
        -    $index++;
        -
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -    my $endTypeIndex = $index;
        -    my @names;
        -    my @types;
        -
        -    for (;;)
        -        {
        -        my $name = $self->TryToGetIdentifier(\$index, \$lineNumber);
        -        if (!$name)
        -            {  return undef;  };
        -
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        my $type;
        -
        -        if ($tokens->[$index] eq ':')
        -            {
        -            $index++;
        -            $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -            $type = ': ' . $self->TryToGetIdentifier(\$index, \$lineNumber, 1);
        -
        -            $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -            };
        -
        -        if ($tokens->[$index] eq '=')
        -            {
        -            do
        -                {
        -                $self->GenericSkip(\$index, \$lineNumber);
        -                }
        -            while ($tokens->[$index] ne ',' && !exists $declarationEnders{$tokens->[$index]} && $index < scalar @$tokens);
        -            };
        -
        -        push @names, $name;
        -        push @types, $type;
        -
        -        if ($tokens->[$index] eq ',')
        -            {
        -            $index++;
        -            $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -            }
        -        elsif (exists $declarationEnders{$tokens->[$index]})
        -            {  last;  }
        -        else
        -            {  return undef;  };
        -        };
        -
        -
        -    # We succeeded if we got this far.
        -
        -    my $prototypePrefix = $self->CreateString($startIndex, $endTypeIndex);
        -
        -    for (my $i = 0; $i < scalar @names; $i++)
        -        {
        -        my $prototype = $self->NormalizePrototype( $prototypePrefix . ' ' . $names[$i] . $types[$i]);
        -        my $scope = $self->CurrentScope();
        -
        -        if ($names[$i] =~ s/^_global.//)
        -            {  $scope = undef;  };
        -        if ($namespace)
        -            {  $scope = NaturalDocs::SymbolString->Join($scope, $namespace);  };
        -
        -        $self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New($type, $names[$i],
        -                                                                                                  $scope, $self->CurrentUsing(),
        -                                                                                                  $prototype,
        -                                                                                                  undef, undef, $startLine));
        -        };
        -
        -    $$indexRef = $index;
        -    $$lineNumberRef = $lineNumber;
        -
        -    return 1;
        -    };
        -
        -
        -
        -################################################################################
        -# Group: Low Level Parsing Functions
        -
        -
        -#
        -#   Function: GenericSkip
        -#
        -#   Advances the position one place through general code.
        -#
        -#   - If the position is on a string, it will skip it completely.
        -#   - If the position is on an opening symbol, it will skip until the past the closing symbol.
        -#   - If the position is on whitespace (including comments), it will skip it completely.
        -#   - Otherwise it skips one token.
        -#
        -#   Parameters:
        -#
        -#       indexRef - A reference to the current index.
        -#       lineNumberRef - A reference to the current line number.
        -#
        -sub GenericSkip #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    # We can ignore the scope stack because we're just skipping everything without parsing, and we need recursion anyway.
        -    if ($tokens->[$$indexRef] eq '{')
        -        {
        -        $$indexRef++;
        -        $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, '}');
        -        }
        -    elsif ($tokens->[$$indexRef] eq '(')
        -        {
        -        $$indexRef++;
        -        $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, ')');
        -        }
        -    elsif ($tokens->[$$indexRef] eq '[')
        -        {
        -        $$indexRef++;
        -        $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, ']');
        -        }
        -
        -    elsif ($self->TryToSkipWhitespace($indexRef, $lineNumberRef) ||
        -            $self->TryToSkipString($indexRef, $lineNumberRef) ||
        -            $self->TryToSkipRegExp($indexRef, $lineNumberRef) ||
        -            $self->TryToSkipXML($indexRef, $lineNumberRef) )
        -        {
        -        }
        -
        -    else
        -        {  $$indexRef++;  };
        -    };
        -
        -
        -#
        -#   Function: GenericSkipUntilAfter
        -#
        -#   Advances the position via <GenericSkip()> until a specific token is reached and passed.
        -#
        -sub GenericSkipUntilAfter #(indexRef, lineNumberRef, token)
        -    {
        -    my ($self, $indexRef, $lineNumberRef, $token) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    while ($$indexRef < scalar @$tokens && $tokens->[$$indexRef] ne $token)
        -        {  $self->GenericSkip($indexRef, $lineNumberRef);  };
        -
        -    if ($tokens->[$$indexRef] eq "\n")
        -        {  $$lineNumberRef++;  };
        -    $$indexRef++;
        -    };
        -
        -
        -#
        -#   Function: IndiscriminateSkipUntilAfterSequence
        -#
        -#   Advances the position indiscriminately until a specific token sequence is reached and passed.
        -#
        -sub IndiscriminateSkipUntilAfterSequence #(indexRef, lineNumberRef, token, token, ...)
        -    {
        -    my ($self, $indexRef, $lineNumberRef, @sequence) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    while ($$indexRef < scalar @$tokens && !$self->IsAtSequence($$indexRef, @sequence))
        -        {
        -        if ($tokens->[$$indexRef] eq "\n")
        -            {  $$lineNumberRef++;  };
        -        $$indexRef++;
        -        };
        -
        -    if ($self->IsAtSequence($$indexRef, @sequence))
        -        {
        -        $$indexRef += scalar @sequence;
        -        foreach my $token (@sequence)
        -            {
        -            if ($token eq "\n")
        -                {  $$lineNumberRef++;  };
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: SkipToNextStatement
        -#
        -#   Advances the position via <GenericSkip()> until the next statement, which is defined as anything in <declarationEnders> not
        -#   appearing in brackets or strings.  It will always advance at least one token.
        -#
        -sub SkipToNextStatement #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($tokens->[$$indexRef] eq ';')
        -        {  $$indexRef++;  }
        -
        -    else
        -        {
        -        do
        -            {
        -            $self->GenericSkip($indexRef, $lineNumberRef);
        -            }
        -        while ( $$indexRef < scalar @$tokens &&
        -                  !exists $declarationEnders{$tokens->[$$indexRef]} );
        -        };
        -    };
        -
        -
        -#
        -#   Function: TryToSkipRegExp
        -#   If the current position is on a regular expression, skip past it and return true.
        -#
        -sub TryToSkipRegExp #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($tokens->[$$indexRef] eq '/')
        -        {
        -        # A slash can either start a regular expression or be a divide symbol.  Skip backwards to see what the previous symbol is.
        -        my $index = $$indexRef - 1;
        -
        -        while ($index >= 0 && $tokens->[$index] =~ /^(?: |\t|\n)/)
        -            {  $index--;  };
        -
        -        if ($index < 0 || $tokens->[$index] !~ /^[\:\=\(\[\,]/)
        -            {  return 0;  };
        -
        -        $$indexRef++;
        -
        -        while ($$indexRef < scalar @$tokens && $tokens->[$$indexRef] ne '/')
        -            {
        -            if ($tokens->[$$indexRef] eq '\\')
        -                {  $$indexRef += 2;  }
        -            elsif ($tokens->[$$indexRef] eq "\n")
        -                {
        -                $$indexRef++;
        -                $$lineNumberRef++;
        -                }
        -            else
        -                {  $$indexRef++;  }
        -            };
        -
        -        if ($$indexRef < scalar @$tokens)
        -            {
        -            $$indexRef++;
        -
        -            if ($tokens->[$$indexRef] =~ /^[gimsx]+$/i)
        -                {  $$indexRef++;  };
        -            };
        -
        -        return 1;
        -        }
        -    else
        -        {  return 0;  };
        -    };
        -
        -
        -#
        -#   Function: TryToSkipXML
        -#   If the current position is on an XML literal, skip past it and return true.
        -#
        -sub TryToSkipXML #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($tokens->[$$indexRef] eq '<')
        -        {
        -        # A < can either start an XML literal or be a comparison or shift operator.  First check the next character for << or <=.
        -
        -        my $index = $$indexRef + 1;
        -
        -        while ($index < scalar @$tokens && $tokens->[$index] =~ /^[\=\<]$/)
        -            {  return 0;  };
        -
        -
        -        # Next try the previous character.
        -
        -        $index = $$indexRef - 1;
        -
        -        while ($index >= 0 && $tokens->[$index] =~ /^[ |\t|\n]/)
        -            {  $index--;  };
        -
        -        if ($index < 0 || $tokens->[$index] !~ /^[\=\(\[\,\>]/)
        -            {  return 0;  };
        -        }
        -    else
        -        {  return 0;  };
        -
        -
        -    # Only handle the tag here if it's not an irregular XML section.
        -    if (!$self->TryToSkipIrregularXML($indexRef, $lineNumberRef))
        -        {
        -        my @tagStack;
        -
        -        my ($tagType, $tagIdentifier) = $self->GetAndSkipXMLTag($indexRef, $lineNumberRef);
        -        if ($tagType == XML_OPENING_TAG)
        -            {  push @tagStack, $tagIdentifier;  };
        -
        -        while (scalar @tagStack && $$indexRef < scalar @$tokens)
        -            {
        -            $self->SkipToNextXMLTag($indexRef, $lineNumberRef);
        -            ($tagType, $tagIdentifier) = $self->GetAndSkipXMLTag($indexRef, $lineNumberRef);
        -
        -            if ($tagType == XML_OPENING_TAG)
        -                {  push @tagStack, $tagIdentifier;  }
        -            elsif ($tagType == XML_CLOSING_TAG && $tagIdentifier eq $tagStack[-1])
        -                {  pop @tagStack;  };
        -            };
        -        };
        -
        -
        -    return 1;
        -    };
        -
        -
        -#
        -#   Function: TryToSkipIrregularXML
        -#
        -#   If the current position is on an irregular XML tag, skip past it and return true.  Irregular XML tags are defined as
        -#
        -#       CDATA - <![CDATA[ ... ]]>
        -#       Comments - <!-- ... -->
        -#       PI - <? ... ?>
        -#
        -sub TryToSkipIrregularXML #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -
        -    if ($self->IsAtSequence($$indexRef, '<', '!', '[', 'CDATA', '['))
        -        {
        -        $$indexRef += 5;
        -        $self->IndiscriminateSkipUntilAfterSequence($indexRef, $lineNumberRef, ']', ']', '>');
        -        return 1;
        -        }
        -
        -    elsif ($self->IsAtSequence($$indexRef, '<', '!', '-', '-'))
        -        {
        -        $$indexRef += 4;
        -        $self->IndiscriminateSkipUntilAfterSequence($indexRef, $lineNumberRef, '-', '-', '>');
        -        return 1;
        -        }
        -
        -    elsif ($self->IsAtSequence($$indexRef, '<', '?'))
        -        {
        -        $$indexRef += 2;
        -        $self->IndiscriminateSkipUntilAfterSequence($indexRef, $lineNumberRef, '?', '>');
        -        return 1;
        -        }
        -
        -    else
        -        {  return 0;  };
        -    };
        -
        -
        -#
        -#   Function: GetAndSkipXMLTag
        -#
        -#   Processes the XML tag at the current position, moves beyond it, and returns information about it.  Assumes the position is on
        -#   the opening angle bracket of the tag and the tag is a normal XML tag, not one of the ones handled by
        -#   <TryToSkipIrregularXML()>.
        -#
        -#   Parameters:
        -#
        -#       indexRef - A reference to the index of the position of the opening angle bracket.
        -#       lineNumberRef - A reference to the line number of the position of the opening angle bracket.
        -#
        -#   Returns:
        -#
        -#       The array ( tagType, name ).
        -#
        -#       tagType - One of the <XML Tag Type> constants.
        -#       identifier - The identifier of the tag.  If it's an empty tag (<> or </>), this will be "(anonymous)".
        -#
        -sub GetAndSkipXMLTag #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($$indexRef < scalar @$tokens && $tokens->[$$indexRef] ne '<')
        -        {  die "Tried to call GetXMLTag when the position isn't on an opening bracket.";  };
        -
        -    # Get the anonymous ones out of the way so we don't have to worry about them below, since they're rather exceptional.
        -
        -    if ($self->IsAtSequence($$indexRef, '<', '>'))
        -        {
        -        $$indexRef += 2;
        -        return ( XML_OPENING_TAG, '(anonymous)' );
        -        }
        -    elsif ($self->IsAtSequence($$indexRef, '<', '/', '>'))
        -        {
        -        $$indexRef += 3;
        -        return ( XML_CLOSING_TAG, '(anonymous)' );
        -        };
        -
        -
        -    # Grab the identifier.
        -
        -    my $tagType = XML_OPENING_TAG;
        -    my $identifier;
        -
        -    $$indexRef++;
        -
        -    if ($tokens->[$$indexRef] eq '/')
        -        {
        -        $$indexRef++;
        -        $tagType = XML_CLOSING_TAG;
        -        };
        -
        -    $self->TryToSkipXMLWhitespace($indexRef, $lineNumberRef);
        -
        -
        -    # The identifier could be a native expression in braces.
        -
        -    if ($tokens->[$$indexRef] eq '{')
        -        {
        -        my $startOfIdentifier = $$indexRef;
        -
        -        $$indexRef++;
        -        $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, '}');
        -
        -        $identifier = $self->CreateString($startOfIdentifier, $$indexRef);
        -        }
        -
        -
        -    # Otherwise just grab content until whitespace or the end of the tag.
        -
        -    else
        -        {
        -        while ($$indexRef < scalar @$tokens && $tokens->[$$indexRef] !~ /^[\/\>\ \t]$/)
        -            {
        -            $identifier .= $tokens->[$$indexRef];
        -            $$indexRef++;
        -            };
        -        };
        -
        -
        -    # Skip to the end of the tag.
        -
        -    while ($$indexRef < scalar @$tokens && $tokens->[$$indexRef] !~ /^[\/\>]$/)
        -        {
        -        if ($tokens->[$$indexRef] eq '{')
        -            {
        -            $$indexRef++;
        -            $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, '}');
        -            }
        -
        -        elsif ($self->TryToSkipXMLWhitespace($indexRef, $lineNumberRef))
        -            {  }
        -
        -        # We don't need to do special handling for attribute quotes or anything like that because there's no backslashing in
        -        # XML.  It's all handled with entity characters.
        -        else
        -            {  $$indexRef++;  };
        -        };
        -
        -
        -    if ($tokens->[$$indexRef] eq '/')
        -        {
        -        if ($tagType == XML_OPENING_TAG)
        -            {  $tagType = XML_SELF_CONTAINED_TAG;  };
        -
        -        $$indexRef++;
        -        };
        -
        -    if ($tokens->[$$indexRef] eq '>')
        -        {  $$indexRef++;  };
        -
        -    if (!$identifier)
        -        {  $identifier = '(anonymous)';  };
        -
        -
        -    return ( $tagType, $identifier );
        -    };
        -
        -
        -#
        -#   Function: SkipToNextXMLTag
        -#   Skips to the next normal XML tag.  It will not stop at elements handled by <TryToSkipIrregularXML()>.  Note that if the
        -#   position is already at an XML tag, it will not move.
        -#
        -sub SkipToNextXMLTag #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    while ($$indexRef < scalar @$tokens)
        -        {
        -        if ($tokens->[$$indexRef] eq '{')
        -            {
        -            $$indexRef++;
        -            $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, '}');
        -            }
        -
        -        elsif ($self->TryToSkipIrregularXML($indexRef, $lineNumberRef))
        -            {  }
        -
        -        elsif ($tokens->[$$indexRef] eq '<')
        -            {  last;  }
        -
        -        else
        -            {
        -            if ($tokens->[$$indexRef] eq "\n")
        -                {  $$lineNumberRef++;  };
        -
        -            $$indexRef++;
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: TryToSkipXMLWhitespace
        -#   If the current position is on XML whitespace, skip past it and return true.
        -#
        -sub TryToSkipXMLWhitespace #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $result;
        -
        -    while ($$indexRef < scalar @$tokens)
        -        {
        -        if ($tokens->[$$indexRef] =~ /^[ \t]/)
        -            {
        -            $$indexRef++;
        -            $result = 1;
        -            }
        -        elsif ($tokens->[$$indexRef] eq "\n")
        -            {
        -            $$indexRef++;
        -            $$lineNumberRef++;
        -            $result = 1;
        -            }
        -        else
        -            {  last;  };
        -        };
        -
        -    return $result;
        -    };
        -
        -
        -#
        -#   Function: TryToSkipString
        -#   If the current position is on a string delimiter, skip past the string and return true.
        -#
        -#   Parameters:
        -#
        -#       indexRef - A reference to the index of the position to start at.
        -#       lineNumberRef - A reference to the line number of the position.
        -#
        -#   Returns:
        -#
        -#       Whether the position was at a string.
        -#
        -#   Syntax Support:
        -#
        -#       - Supports quotes and apostrophes.
        -#
        -sub TryToSkipString #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -
        -    return ($self->SUPER::TryToSkipString($indexRef, $lineNumberRef, '\'') ||
        -               $self->SUPER::TryToSkipString($indexRef, $lineNumberRef, '"') );
        -    };
        -
        -
        -#
        -#   Function: TryToSkipWhitespace
        -#   If the current position is on a whitespace token, a line break token, or a comment, it skips them and returns true.  If there are
        -#   a number of these in a row, it skips them all.
        -#
        -sub TryToSkipWhitespace #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $result;
        -
        -    while ($$indexRef < scalar @$tokens)
        -        {
        -        if ($tokens->[$$indexRef] =~ /^[ \t]/)
        -            {
        -            $$indexRef++;
        -            $result = 1;
        -            }
        -        elsif ($tokens->[$$indexRef] eq "\n")
        -            {
        -            $$indexRef++;
        -            $$lineNumberRef++;
        -            $result = 1;
        -            }
        -        elsif ($self->TryToSkipComment($indexRef, $lineNumberRef))
        -            {
        -            $result = 1;
        -            }
        -        else
        -            {  last;  };
        -        };
        -
        -    return $result;
        -    };
        -
        -
        -#
        -#   Function: TryToSkipComment
        -#   If the current position is on a comment, skip past it and return true.
        -#
        -sub TryToSkipComment #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -
        -    return ( $self->TryToSkipLineComment($indexRef, $lineNumberRef) ||
        -                $self->TryToSkipMultilineComment($indexRef, $lineNumberRef) );
        -    };
        -
        -
        -#
        -#   Function: TryToSkipLineComment
        -#   If the current position is on a line comment symbol, skip past it and return true.
        -#
        -sub TryToSkipLineComment #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($tokens->[$$indexRef] eq '/' && $tokens->[$$indexRef+1] eq '/')
        -        {
        -        $self->SkipRestOfLine($indexRef, $lineNumberRef);
        -        return 1;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: TryToSkipMultilineComment
        -#   If the current position is on an opening comment symbol, skip past it and return true.
        -#
        -sub TryToSkipMultilineComment #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($tokens->[$$indexRef] eq '/' && $tokens->[$$indexRef+1] eq '*')
        -        {
        -        $self->SkipUntilAfter($indexRef, $lineNumberRef, '*', '/');
        -        return 1;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Ada.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages/Ada.pm
        deleted file mode 100644
        index 062c5ae97..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Ada.pm
        +++ /dev/null
        @@ -1,39 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Languages::Ada
        -#
        -###############################################################################
        -#
        -#   A subclass to handle the language variations of Ada
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Languages::Ada;
        -
        -use base 'NaturalDocs::Languages::Simple';
        -
        -
        -#
        -#   Function: ParseParameterLine
        -#   Overridden because Ada uses Pascal-style parameters
        -#
        -sub ParseParameterLine #(...)
        -    {
        -    my ($self, @params) = @_;
        -    return $self->SUPER::ParsePascalParameterLine(@params);
        -    };
        -
        -sub TypeBeforeParameter
        -    {
        -    return 0;
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Advanced.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages/Advanced.pm
        deleted file mode 100644
        index d6cafa7eb..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Advanced.pm
        +++ /dev/null
        @@ -1,817 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Languages::Advanced
        -#
        -###############################################################################
        -#
        -#   The base class for all languages that have full support in Natural Docs.  Each one will have a custom parser capable
        -#   of documenting undocumented aspects of the code.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -use NaturalDocs::Languages::Advanced::Scope;
        -use NaturalDocs::Languages::Advanced::ScopeChange;
        -
        -package NaturalDocs::Languages::Advanced;
        -
        -use base 'NaturalDocs::Languages::Base';
        -
        -
        -#############################################################################
        -# Group: Implementation
        -
        -#
        -#   Constants: Members
        -#
        -#   The class is implemented as a blessed arrayref.  The following constants are used as indexes.
        -#
        -#   TOKENS - An arrayref of tokens used in all the <Parsing Functions>.
        -#   SCOPE_STACK - An arrayref of <NaturalDocs::Languages::Advanced::Scope> objects serving as a scope stack for parsing.
        -#                            There will always be one available, with a symbol of undef, for the top level.
        -#   SCOPE_RECORD - An arrayref of <NaturalDocs::Languages::Advanced::ScopeChange> objects, as generated by the scope
        -#                              stack.  If there is more than one change per line, only the last is stored.
        -#   AUTO_TOPICS - An arrayref of <NaturalDocs::Parser::ParsedTopics> generated automatically from the code.
        -#
        -use NaturalDocs::DefineMembers 'TOKENS', 'SCOPE_STACK', 'SCOPE_RECORD', 'AUTO_TOPICS';
        -
        -
        -#############################################################################
        -# Group: Functions
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -#   Parameters:
        -#
        -#       name - The name of the language.
        -#
        -sub New #(name)
        -    {
        -    my ($package, @parameters) = @_;
        -
        -    my $object = $package->SUPER::New(@parameters);
        -    $object->[TOKENS] = undef;
        -    $object->[SCOPE_STACK] = undef;
        -    $object->[SCOPE_RECORD] = undef;
        -
        -    return $object;
        -    };
        -
        -
        -# Function: Tokens
        -# Returns the tokens found by <ParseForCommentsAndTokens()>.
        -sub Tokens
        -    {  return $_[0]->[TOKENS];  };
        -
        -# Function: SetTokens
        -# Replaces the tokens.
        -sub SetTokens #(tokens)
        -    {  $_[0]->[TOKENS] = $_[1];  };
        -
        -# Function: ClearTokens
        -#  Resets the token list.  You may want to do this after parsing is over to save memory.
        -sub ClearTokens
        -    {  $_[0]->[TOKENS] = undef;  };
        -
        -# Function: AutoTopics
        -# Returns the arrayref of automatically generated topics, or undef if none.
        -sub AutoTopics
        -    {  return $_[0]->[AUTO_TOPICS];  };
        -
        -# Function: AddAutoTopic
        -# Adds a <NaturalDocs::Parser::ParsedTopic> to <AutoTopics()>.
        -sub AddAutoTopic #(topic)
        -    {
        -    my ($self, $topic) = @_;
        -    if (!defined $self->[AUTO_TOPICS])
        -        {  $self->[AUTO_TOPICS] = [ ];  };
        -    push @{$self->[AUTO_TOPICS]}, $topic;
        -    };
        -
        -# Function: ClearAutoTopics
        -# Resets the automatic topic list.  Not necessary if you call <ParseForCommentsAndTokens()>.
        -sub ClearAutoTopics
        -    {  $_[0]->[AUTO_TOPICS] = undef;  };
        -
        -# Function: ScopeRecord
        -# Returns an arrayref of <NaturalDocs::Languages::Advanced::ScopeChange> objects describing how and when the scope
        -# changed thoughout the file.  There will always be at least one entry, which will be for line 1 and undef as the scope.
        -sub ScopeRecord
        -    {  return $_[0]->[SCOPE_RECORD];  };
        -
        -
        -
        -###############################################################################
        -#
        -#   Group: Parsing Functions
        -#
        -#   These functions are good general language building blocks.  Use them to create your language-specific parser.
        -#
        -#   All functions work on <Tokens()> and assume it is set by <ParseForCommentsAndTokens()>.
        -#
        -
        -
        -#
        -#   Function: ParseForCommentsAndTokens
        -#
        -#   Loads the passed file, sends all appropriate comments to <NaturalDocs::Parser->OnComment()>, and breaks the rest into
        -#   an arrayref of tokens.  Tokens are defined as
        -#
        -#   - All consecutive alphanumeric and underscore characters.
        -#   - All consecutive whitespace.
        -#   - A single line break.  It will always be "\n"; you don't have to worry about platform differences.
        -#   - A single character not included above, which is usually a symbol.  Multiple consecutive ones each get their own token.
        -#
        -#   The result will be placed in <Tokens()>.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The source <FileName> to load and parse.
        -#       lineCommentSymbols - An arrayref of symbols that designate line comments, or undef if none.
        -#       blockCommentSymbols - An arrayref of symbol pairs that designate multiline comments, or undef if none.  Symbol pairs are
        -#                                            designated as two consecutive array entries, the opening symbol appearing first.
        -#       javadocLineCommentSymbols - An arrayref of symbols that designate the start of a JavaDoc comment, or undef if none.
        -#       javadocBlockCommentSymbols - An arrayref of symbol pairs that designate multiline JavaDoc comments, or undef if none.
        -#
        -#   Notes:
        -#
        -#       - This function automatically calls <ClearAutoTopics()> and <ClearScopeStack()>.  You only need to call those functions
        -#         manually if you override this one.
        -#       - To save parsing time, all comment lines sent to <NaturalDocs::Parser->OnComment()> will be replaced with blank lines
        -#         in <Tokens()>.  It's all the same to most languages.
        -#
        -sub ParseForCommentsAndTokens #(FileName sourceFile, string[] lineCommentSymbols, string[] blockCommentSymbols, string[] javadocLineCommentSymbols, string[] javadocBlockCommentSymbols)
        -    {
        -    my ($self, $sourceFile, $lineCommentSymbols, $blockCommentSymbols,
        -           $javadocLineCommentSymbols, $javadocBlockCommentSymbols) = @_;
        -
        -    open(SOURCEFILEHANDLE, '<' . $sourceFile)
        -        or die "Couldn't open input file " . $sourceFile . "\n";
        -
        -    my $lineReader = NaturalDocs::LineReader->New(\*SOURCEFILEHANDLE);
        -
        -    my $tokens = [ ];
        -    $self->SetTokens($tokens);
        -
        -    # For convenience.
        -    $self->ClearAutoTopics();
        -    $self->ClearScopeStack();
        -
        -
        -    # Load and preprocess the file
        -
        -    my @lines = $lineReader->GetAll();
        -    close(SOURCEFILEHANDLE);
        -
        -    $self->PreprocessFile(\@lines);
        -
        -
        -    # Go through the file
        -
        -    my $lineIndex = 0;
        -
        -    while ($lineIndex < scalar @lines)
        -        {
        -        my $line = $lines[$lineIndex];
        -
        -        my @commentLines;
        -        my $commentLineNumber;
        -        my $isJavaDoc;
        -        my $closingSymbol;
        -
        -
        -        # Retrieve single line comments.  This leaves $lineIndex at the next line.
        -
        -        if ( ($isJavaDoc = $self->StripOpeningJavaDocSymbols(\$line, $javadocLineCommentSymbols)) ||
        -              $self->StripOpeningSymbols(\$line, $lineCommentSymbols))
        -            {
        -            $commentLineNumber = $lineIndex + 1;
        -
        -            do
        -                {
        -                push @commentLines, $line;
        -                push @$tokens, "\n";
        -
        -                $lineIndex++;
        -
        -                if ($lineIndex >= scalar @lines)
        -                    {  goto EndDo;  };
        -
        -                $line = $lines[$lineIndex];
        -                }
        -            while ($self->StripOpeningSymbols(\$line, $lineCommentSymbols));
        -
        -            EndDo:  # I hate Perl sometimes.
        -            }
        -
        -
        -        # Retrieve multiline comments.  This leaves $lineIndex at the next line.
        -
        -        elsif ( ($isJavaDoc = $self->StripOpeningJavaDocBlockSymbols(\$line, $javadocBlockCommentSymbols)) ||
        -                 ($closingSymbol = $self->StripOpeningBlockSymbols(\$line, $blockCommentSymbols)) )
        -            {
        -            $commentLineNumber = $lineIndex + 1;
        -
        -            if ($isJavaDoc)
        -                {  $closingSymbol = $isJavaDoc;  };
        -
        -            # Note that it is possible for a multiline comment to start correctly but not end so.  We want those comments to stay in
        -            # the code.  For example, look at this prototype with this splint annotation:
        -            #
        -            # int get_array(integer_t id,
        -            #                    /*@out@*/ array_t array);
        -            #
        -            # The annotation starts correctly but doesn't end so because it is followed by code on the same line.
        -
        -            my ($lineRemainder, $isMultiLine);
        -
        -            for (;;)
        -                {
        -                $lineRemainder = $self->StripClosingSymbol(\$line, $closingSymbol);
        -
        -                push @commentLines, $line;
        -
        -                #  If we found an end comment symbol...
        -                if (defined $lineRemainder)
        -                    {  last;  };
        -
        -                push @$tokens, "\n";
        -                $lineIndex++;
        -                $isMultiLine = 1;
        -
        -                if ($lineIndex >= scalar @lines)
        -                    {  last;  };
        -
        -                $line = $lines[$lineIndex];
        -                };
        -
        -            if ($lineRemainder !~ /^[ \t]*$/)
        -                {
        -                # If there was something past the closing symbol this wasn't an acceptable comment.
        -
        -                if ($isMultiLine)
        -                    {  $self->TokenizeLine($lineRemainder);  }
        -                else
        -                    {
        -                    # We go back to the original line if it wasn't a multiline comment because we want the comment to stay in the
        -                    # code.  Otherwise the /*@out@*/ from the example would be removed.
        -                    $self->TokenizeLine($lines[$lineIndex]);
        -                    };
        -
        -                @commentLines = ( );
        -                }
        -            else
        -                {
        -                push @$tokens, "\n";
        -                };
        -
        -            $lineIndex++;
        -            }
        -
        -
        -        # Otherwise just add it to the code.
        -
        -        else
        -            {
        -            $self->TokenizeLine($line);
        -            $lineIndex++;
        -            };
        -
        -
        -        # If there were comments, send them to Parser->OnComment().
        -
        -        if (scalar @commentLines)
        -            {
        -            NaturalDocs::Parser->OnComment(\@commentLines, $commentLineNumber, $isJavaDoc);
        -            @commentLines = ( );
        -            $isJavaDoc = undef;
        -            };
        -
        -        # $lineIndex was incremented by the individual code paths above.
        -
        -        };  # while ($lineIndex < scalar @lines)
        -    };
        -
        -
        -#
        -#   Function: PreprocessFile
        -#
        -#   An overridable function if you'd like to preprocess the file before it goes into <ParseForCommentsAndTokens()>.
        -#
        -#   Parameters:
        -#
        -#       lines - An arrayref to the file's lines.  Each line has its line break stripped off, but is otherwise untouched.
        -#
        -sub PreprocessFile #(lines)
        -    {
        -    };
        -
        -
        -#
        -#   Function: TokenizeLine
        -#
        -#   Converts the passed line to tokens as described in <ParseForCommentsAndTokens> and adds them to <Tokens()>.  Also
        -#   adds a line break token after it.
        -#
        -sub TokenizeLine #(line)
        -    {
        -    my ($self, $line) = @_;
        -    push @{$self->Tokens()}, $line =~ /(\w+|[ \t]+|.)/g, "\n";
        -    };
        -
        -
        -#
        -#   Function: TryToSkipString
        -#
        -#   If the position is on a string delimiter, moves the position to the token following the closing delimiter, or past the end of the
        -#   tokens if there is none.  Assumes all other characters are allowed in the string, the delimiter itself is allowed if it's preceded by
        -#   a backslash, and line breaks are allowed in the string.
        -#
        -#   Parameters:
        -#
        -#       indexRef - A reference to the position's index into <Tokens()>.
        -#       lineNumberRef - A reference to the position's line number.
        -#       openingDelimiter - The opening string delimiter, such as a quote or an apostrophe.
        -#       closingDelimiter - The closing string delimiter, if different.  If not defined, assumes the same as openingDelimiter.
        -#       startContentIndexRef - A reference to a variable in which to store the index of the first token of the string's content.
        -#                                         May be undef.
        -#       endContentIndexRef - A reference to a variable in which to store the index of the end of the string's content, which is one
        -#                                        past the last index of content.  May be undef.
        -#
        -#   Returns:
        -#
        -#       Whether the position was on the passed delimiter or not.  The index, line number, and content index ref variables will be
        -#       updated only if true.
        -#
        -sub TryToSkipString #(indexRef, lineNumberRef, openingDelimiter, closingDelimiter, startContentIndexRef, endContentIndexRef)
        -    {
        -    my ($self, $index, $lineNumber, $openingDelimiter, $closingDelimiter, $startContentIndexRef, $endContentIndexRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if (!defined $closingDelimiter)
        -        {  $closingDelimiter = $openingDelimiter;  };
        -
        -    if ($tokens->[$$index] ne $openingDelimiter)
        -        {  return undef;  };
        -
        -
        -    $$index++;
        -    if (defined $startContentIndexRef)
        -        {  $$startContentIndexRef = $$index;  };
        -
        -    while ($$index < scalar @$tokens)
        -        {
        -        if ($tokens->[$$index] eq "\\")
        -            {
        -            # Skip the token after it.
        -            $$index += 2;
        -            }
        -        elsif ($tokens->[$$index] eq "\n")
        -            {
        -            $$lineNumber++;
        -            $$index++;
        -            }
        -        elsif ($tokens->[$$index] eq $closingDelimiter)
        -            {
        -            if (defined $endContentIndexRef)
        -                {  $$endContentIndexRef = $$index;  };
        -
        -            $$index++;
        -            last;
        -            }
        -        else
        -            {
        -            $$index++;
        -            };
        -        };
        -
        -    if ($$index >= scalar @$tokens && defined $endContentIndexRef)
        -        {  $$endContentIndexRef = scalar @$tokens;  };
        -
        -    return 1;
        -    };
        -
        -
        -#
        -#   Function: SkipRestOfLine
        -#
        -#   Moves the position to the token following the next line break, or past the end of the tokens array if there is none.  Useful for
        -#   line comments.
        -#
        -#   Note that it skips blindly.  It assumes there cannot be anything of interest, such as a string delimiter, between the position
        -#   and the end of the line.
        -#
        -#   Parameters:
        -#
        -#       indexRef - A reference to the position's index into <Tokens()>.
        -#       lineNumberRef - A reference to the position's line number.
        -
        -sub SkipRestOfLine #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $index, $lineNumber) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    while ($$index < scalar @$tokens)
        -        {
        -        if ($tokens->[$$index] eq "\n")
        -            {
        -            $$lineNumber++;
        -            $$index++;
        -            last;
        -            }
        -        else
        -            {
        -            $$index++;
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: SkipUntilAfter
        -#
        -#   Moves the position to the token following the next occurance of a particular token sequence, or past the end of the tokens
        -#   array if it never occurs.  Useful for multiline comments.
        -#
        -#   Note that it skips blindly.  It assumes there cannot be anything of interest, such as a string delimiter, between the position
        -#   and the end of the line.
        -#
        -#   Parameters:
        -#
        -#       indexRef - A reference to the position's index.
        -#       lineNumberRef - A reference to the position's line number.
        -#       token - A token that must be matched.  Can be specified multiple times to match a sequence of tokens.
        -#
        -sub SkipUntilAfter #(indexRef, lineNumberRef, token, token, ...)
        -    {
        -    my ($self, $index, $lineNumber, @target) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    while ($$index < scalar @$tokens)
        -        {
        -        if ($tokens->[$$index] eq $target[0] && ($$index + scalar @target) <= scalar @$tokens)
        -            {
        -            my $match = 1;
        -
        -            for (my $i = 1; $i < scalar @target; $i++)
        -                {
        -                if ($tokens->[$$index+$i] ne $target[$i])
        -                    {
        -                    $match = 0;
        -                    last;
        -                    };
        -                };
        -
        -            if ($match)
        -                {
        -                $$index += scalar @target;
        -                return;
        -                };
        -            };
        -
        -        if ($tokens->[$$index] eq "\n")
        -            {
        -            $$lineNumber++;
        -            $$index++;
        -            }
        -        else
        -            {
        -            $$index++;
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: IsFirstLineToken
        -#
        -#   Returns whether the position is at the first token of a line, not including whitespace.
        -#
        -#   Parameters:
        -#
        -#       index - The index of the position.
        -#
        -sub IsFirstLineToken #(index)
        -    {
        -    my ($self, $index) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($index == 0)
        -        {  return 1;  };
        -
        -    $index--;
        -
        -    if ($tokens->[$index] =~ /^[ \t]/)
        -        {  $index--;  };
        -
        -    if ($index <= 0 || $tokens->[$index] eq "\n")
        -        {  return 1;  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: IsLastLineToken
        -#
        -#   Returns whether the position is at the last token of a line, not including whitespace.
        -#
        -#   Parameters:
        -#
        -#       index - The index of the position.
        -#
        -sub IsLastLineToken #(index)
        -    {
        -    my ($self, $index) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    do
        -        {  $index++;  }
        -    while ($index < scalar @$tokens && $tokens->[$index] =~ /^[ \t]/);
        -
        -    if ($index >= scalar @$tokens || $tokens->[$index] eq "\n")
        -        {  return 1;  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: IsAtSequence
        -#
        -#   Returns whether the position is at a sequence of tokens.
        -#
        -#   Parameters:
        -#
        -#       index - The index of the position.
        -#       token - A token to match.  Specify multiple times to specify the sequence.
        -#
        -sub IsAtSequence #(index, token, token, token ...)
        -    {
        -    my ($self, $index, @target) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($index + scalar @target > scalar @$tokens)
        -        {  return undef;  };
        -
        -    for (my $i = 0; $i < scalar @target; $i++)
        -        {
        -        if ($tokens->[$index + $i] ne $target[$i])
        -            {  return undef;  };
        -        };
        -
        -    return 1;
        -    };
        -
        -
        -#
        -#   Function: IsBackslashed
        -#
        -#   Returns whether the position is after a backslash.
        -#
        -#   Parameters:
        -#
        -#       index - The index of the postition.
        -#
        -sub IsBackslashed #(index)
        -    {
        -    my ($self, $index) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($index > 0 && $tokens->[$index - 1] eq "\\")
        -        {  return 1;  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -
        -###############################################################################
        -#
        -#   Group: Scope Functions
        -#
        -#   These functions provide a nice scope stack implementation for language-specific parsers to use.  The default implementation
        -#   makes the following assumptions.
        -#
        -#   - Packages completely replace one another, rather than concatenating.  You need to concatenate manually if that's the
        -#     behavior.
        -#
        -#   - Packages inherit, so if a scope level doesn't set its own, the package is the same as the parent scope's.
        -#
        -
        -
        -#
        -#   Function: ClearScopeStack
        -#
        -#   Clears the scope stack for a new file.  Not necessary if you call <ParseForCommentsAndTokens()>.
        -#
        -sub ClearScopeStack
        -    {
        -    my ($self) = @_;
        -    $self->[SCOPE_STACK] = [ NaturalDocs::Languages::Advanced::Scope->New(undef, undef) ];
        -    $self->[SCOPE_RECORD] = [ NaturalDocs::Languages::Advanced::ScopeChange->New(undef, 1) ];
        -    };
        -
        -
        -#
        -#   Function: StartScope
        -#
        -#   Records a new scope level.
        -#
        -#   Parameters:
        -#
        -#       closingSymbol - The closing symbol of the scope.
        -#       lineNumber - The line number where the scope begins.
        -#       package - The package <SymbolString> of the scope.  Undef means no change.
        -#
        -sub StartScope #(closingSymbol, lineNumber, package)
        -    {
        -    my ($self, $closingSymbol, $lineNumber, $package) = @_;
        -
        -    push @{$self->[SCOPE_STACK]},
        -            NaturalDocs::Languages::Advanced::Scope->New($closingSymbol, $package, $self->CurrentUsing());
        -
        -    $self->AddToScopeRecord($self->CurrentScope(), $lineNumber);
        -    };
        -
        -
        -#
        -#   Function: EndScope
        -#
        -#   Records the end of the current scope level.  Note that this is blind; you need to manually check <ClosingScopeSymbol()> if
        -#   you need to determine if it is correct to do so.
        -#
        -#   Parameters:
        -#
        -#       lineNumber - The line number where the scope ends.
        -#
        -sub EndScope #(lineNumber)
        -    {
        -    my ($self, $lineNumber) = @_;
        -
        -    if (scalar @{$self->[SCOPE_STACK]} > 1)
        -        {  pop @{$self->[SCOPE_STACK]};  };
        -
        -    $self->AddToScopeRecord($self->CurrentScope(), $lineNumber);
        -    };
        -
        -
        -#
        -#   Function: ClosingScopeSymbol
        -#
        -#   Returns the symbol that ends the current scope level, or undef if we are at the top level.
        -#
        -sub ClosingScopeSymbol
        -    {
        -    my ($self) = @_;
        -    return $self->[SCOPE_STACK]->[-1]->ClosingSymbol();
        -    };
        -
        -
        -#
        -#   Function: CurrentScope
        -#
        -#   Returns the current calculated scope, or undef if global.  The default implementation just returns <CurrentPackage()>.  This
        -#   is a separate function because C++ may need to track namespaces and classes separately, and so the current scope would
        -#   be a concatenation of them.
        -#
        -sub CurrentScope
        -    {
        -    return $_[0]->CurrentPackage();
        -    };
        -
        -
        -#
        -#   Function: CurrentPackage
        -#
        -#   Returns the current calculated package or class, or undef if none.
        -#
        -sub CurrentPackage
        -    {
        -    my ($self) = @_;
        -
        -    my $package;
        -
        -    for (my $index = scalar @{$self->[SCOPE_STACK]} - 1; $index >= 0 && !defined $package; $index--)
        -        {
        -        $package = $self->[SCOPE_STACK]->[$index]->Package();
        -        };
        -
        -    return $package;
        -    };
        -
        -
        -#
        -#   Function: SetPackage
        -#
        -#   Sets the package for the current scope level.
        -#
        -#   Parameters:
        -#
        -#       package - The new package <SymbolString>.
        -#       lineNumber - The line number the new package starts on.
        -#
        -sub SetPackage #(package, lineNumber)
        -    {
        -    my ($self, $package, $lineNumber) = @_;
        -    $self->[SCOPE_STACK]->[-1]->SetPackage($package);
        -
        -    $self->AddToScopeRecord($self->CurrentScope(), $lineNumber);
        -    };
        -
        -
        -#
        -#   Function: CurrentUsing
        -#
        -#   Returns the current calculated arrayref of <SymbolStrings> from Using statements, or undef if none.
        -#
        -sub CurrentUsing
        -    {
        -    my ($self) = @_;
        -    return $self->[SCOPE_STACK]->[-1]->Using();
        -    };
        -
        -
        -#
        -#   Function: AddUsing
        -#
        -#   Adds a Using <SymbolString> to the current scope.
        -#
        -sub AddUsing #(using)
        -    {
        -    my ($self, $using) = @_;
        -    $self->[SCOPE_STACK]->[-1]->AddUsing($using);
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -
        -#
        -#   Function: AddToScopeRecord
        -#
        -#   Adds a change to the scope record, condensing unnecessary entries.
        -#
        -#   Parameters:
        -#
        -#       newScope - What the scope <SymbolString> changed to.
        -#       lineNumber - Where the scope changed.
        -#
        -sub AddToScopeRecord #(newScope, lineNumber)
        -    {
        -    my ($self, $scope, $lineNumber) = @_;
        -    my $scopeRecord = $self->ScopeRecord();
        -
        -    if ($scope ne $scopeRecord->[-1]->Scope())
        -        {
        -        if ($scopeRecord->[-1]->LineNumber() == $lineNumber)
        -            {  $scopeRecord->[-1]->SetScope($scope);  }
        -        else
        -            {  push @$scopeRecord, NaturalDocs::Languages::Advanced::ScopeChange->New($scope, $lineNumber);  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: CreateString
        -#
        -#   Converts the specified tokens into a string and returns it.
        -#
        -#   Parameters:
        -#
        -#       startIndex - The starting index to convert.
        -#       endIndex - The ending index, which is *not inclusive*.
        -#
        -#   Returns:
        -#
        -#       The string.
        -#
        -sub CreateString #(startIndex, endIndex)
        -    {
        -    my ($self, $startIndex, $endIndex) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $string;
        -
        -    while ($startIndex < $endIndex && $startIndex < scalar @$tokens)
        -        {
        -        $string .= $tokens->[$startIndex];
        -        $startIndex++;
        -        };
        -
        -    return $string;
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Advanced/Scope.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages/Advanced/Scope.pm
        deleted file mode 100644
        index 39218107b..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Advanced/Scope.pm
        +++ /dev/null
        @@ -1,96 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Languages::Advanced::Scope
        -#
        -###############################################################################
        -#
        -#   A class used to store a scope level.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Languages::Advanced::Scope;
        -
        -#
        -#   Constants: Implementation
        -#
        -#   The object is implemented as a blessed arrayref.  The constants below are used as indexes.
        -#
        -#   CLOSING_SYMBOL - The closing symbol character of the scope.
        -#   PACKAGE - The package <SymbolString> of the scope.
        -#   USING - An arrayref of <SymbolStrings> for using statements, or undef if none.
        -#
        -use NaturalDocs::DefineMembers 'CLOSING_SYMBOL', 'PACKAGE', 'USING';
        -# Dependency: New() depends on the order of these constants as well as that there is no inherited members.
        -
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -#   Parameters:
        -#
        -#       closingSymbol - The closing symbol character of the scope.
        -#       package - The package <SymbolString> of the scope.
        -#       using - An arrayref of using <SymbolStrings>, or undef if none.  The contents of the array will be duplicated.
        -#
        -#       If package is set to undef, it is assumed that it inherits the value of the previous scope on the stack.
        -#
        -sub New #(closingSymbol, package, using)
        -    {
        -    # Dependency: This depends on the order of the parameters matching the constants, and that there are no inherited
        -    # members.
        -    my $package = shift;
        -
        -    my $object = [ @_ ];
        -    bless $object, $package;
        -
        -    if (defined $object->[USING])
        -        {  $object->[USING] = [ @{$object->[USING]} ];  };
        -
        -    return $object;
        -    };
        -
        -
        -# Function: ClosingSymbol
        -# Returns the closing symbol character of the scope.
        -sub ClosingSymbol
        -    {  return $_[0]->[CLOSING_SYMBOL];  };
        -
        -# Function: Package
        -# Returns the package <SymbolString> of the scope, or undef if none.
        -sub Package
        -    {  return $_[0]->[PACKAGE];  };
        -
        -# Function: SetPackage
        -# Sets the package <SymbolString> of the scope.
        -sub SetPackage #(package)
        -    {  $_[0]->[PACKAGE] = $_[1];  };
        -
        -# Function: Using
        -# Returns an arrayref of <SymbolStrings> for using statements, or undef if none
        -sub Using
        -    {  return $_[0]->[USING];  };
        -
        -# Function: AddUsing
        -# Adds a <SymbolString> to the <Using()> array.
        -sub AddUsing #(using)
        -    {
        -    my ($self, $using) = @_;
        -
        -    if (!defined $self->[USING])
        -        {  $self->[USING] = [ ];  };
        -
        -    push @{$self->[USING]}, $using;
        -    };
        -
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Advanced/ScopeChange.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages/Advanced/ScopeChange.pm
        deleted file mode 100644
        index 8774d5b59..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Advanced/ScopeChange.pm
        +++ /dev/null
        @@ -1,71 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Languages::Advanced::ScopeChange
        -#
        -###############################################################################
        -#
        -#   A class used to store a scope change.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Languages::Advanced::ScopeChange;
        -
        -#
        -#   Constants: Implementation
        -#
        -#   The object is implemented as a blessed arrayref.  The constants below are used as indexes.
        -#
        -#   SCOPE - The new scope <SymbolString>.
        -#   LINE_NUMBER - The line number of the change.
        -#
        -use NaturalDocs::DefineMembers 'SCOPE', 'LINE_NUMBER';
        -# Dependency: New() depends on the order of these constants as well as that there is no inherited members.
        -
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -#   Parameters:
        -#
        -#       scope - The <SymbolString> the scope was changed to.
        -#       lineNumber - What line it occurred on.
        -#
        -sub New #(scope, lineNumber)
        -    {
        -    # Dependency: This depends on the order of the parameters matching the constants, and that there are no inherited
        -    # members.
        -    my $self = shift;
        -
        -    my $object = [ @_ ];
        -    bless $object, $self;
        -
        -    return $object;
        -    };
        -
        -
        -# Function: Scope
        -# Returns the <SymbolString> the scope was changed to.
        -sub Scope
        -    {  return $_[0]->[SCOPE];  };
        -
        -# Function: SetScope
        -# Replaces the <SymbolString> the scope was changed to.
        -sub SetScope #(scope)
        -    {  $_[0]->[SCOPE] = $_[1];  };
        -
        -# Function: LineNumber
        -# Returns the line number of the change.
        -sub LineNumber
        -    {  return $_[0]->[LINE_NUMBER];  };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Base.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages/Base.pm
        deleted file mode 100644
        index 15880c437..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Base.pm
        +++ /dev/null
        @@ -1,833 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Languages::Base
        -#
        -###############################################################################
        -#
        -#   A base class for all programming language parsers.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Languages::Base;
        -
        -use NaturalDocs::DefineMembers 'NAME', 'Name()',
        -                                                 'EXTENSIONS', 'Extensions()', 'SetExtensions() duparrayref',
        -                                                 'SHEBANG_STRINGS', 'ShebangStrings()', 'SetShebangStrings() duparrayref',
        -                                                 'IGNORED_PREFIXES',
        -                                                 'ENUM_VALUES';
        -
        -use base 'Exporter';
        -our @EXPORT = ('ENUM_GLOBAL', 'ENUM_UNDER_TYPE', 'ENUM_UNDER_PARENT');
        -
        -
        -#
        -#   Constants: EnumValuesType
        -#
        -#   How enum values are handled in the language.
        -#
        -#   ENUM_GLOBAL - Values are always global and thus 'value'.
        -#   ENUM_UNDER_TYPE - Values are under the type in the hierarchy, and thus 'package.enum.value'.
        -#   ENUM_UNDER_PARENT - Values are under the parent in the hierarchy, putting them on the same level as the enum itself.  Thus
        -#                                       'package.value'.
        -#
        -use constant ENUM_GLOBAL => 1;
        -use constant ENUM_UNDER_TYPE => 2;
        -use constant ENUM_UNDER_PARENT => 3;
        -
        -
        -#
        -#   Handle: SOURCEFILEHANDLE
        -#
        -#   The handle of the source file currently being parsed.
        -#
        -
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -#   Parameters:
        -#
        -#       name - The name of the language.
        -#
        -sub New #(name)
        -    {
        -    my ($selfPackage, $name) = @_;
        -
        -    my $object = [ ];
        -
        -    $object->[NAME] = $name;
        -
        -    bless $object, $selfPackage;
        -    return $object;
        -    };
        -
        -
        -#
        -#   Functions: Members
        -#
        -#   Name - Returns the language's name.
        -#   Extensions - Returns an arrayref of the language's file extensions, or undef if none.
        -#   SetExtensions - Replaces the arrayref of the language's file extensions.
        -#   ShebangStrings - Returns an arrayref of the language's shebang strings, or undef if none.
        -#   SetShebangStrings - Replaces the arrayref of the language's shebang strings.
        -#
        -
        -#
        -#   Function: PackageSeparator
        -#   Returns the language's package separator string.
        -#
        -sub PackageSeparator
        -    {  return '.';  };
        -
        -#
        -#   Function: PackageSeparatorWasSet
        -#   Returns whether the language's package separator string was ever changed from the default.
        -#
        -sub PackageSeparatorWasSet
        -    {  return 0;  };
        -
        -
        -#
        -#   Function: EnumValues
        -#   Returns the <EnumValuesType> that describes how the language handles enums.
        -#
        -sub EnumValues
        -    {  return ENUM_GLOBAL;  };
        -
        -
        -#
        -#   Function: IgnoredPrefixesFor
        -#
        -#   Returns an arrayref of ignored prefixes for the passed <TopicType>, or undef if none.  The array is sorted so that the longest
        -#   prefixes are first.
        -#
        -sub IgnoredPrefixesFor #(type)
        -    {
        -    my ($self, $type) = @_;
        -
        -    if (defined $self->[IGNORED_PREFIXES])
        -        {  return $self->[IGNORED_PREFIXES]->{$type};  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: SetIgnoredPrefixesFor
        -#
        -#   Replaces the arrayref of ignored prefixes for the passed <TopicType>.
        -#
        -sub SetIgnoredPrefixesFor #(type, prefixes)
        -    {
        -    my ($self, $type, $prefixesRef) = @_;
        -
        -    if (!defined $self->[IGNORED_PREFIXES])
        -        {  $self->[IGNORED_PREFIXES] = { };  };
        -
        -    if (!defined $prefixesRef)
        -        {  delete $self->[IGNORED_PREFIXES]->{$type};  }
        -    else
        -        {
        -        my $prefixes = [ @$prefixesRef ];
        -
        -        # Sort prefixes to be longest to shortest.
        -        @$prefixes = sort { length $b <=> length $a } @$prefixes;
        -
        -        $self->[IGNORED_PREFIXES]->{$type} = $prefixes;
        -        };
        -    };
        -
        -
        -#
        -#   Function: HasIgnoredPrefixes
        -#
        -#   Returns whether the language has any ignored prefixes at all.
        -#
        -sub HasIgnoredPrefixes
        -    {  return defined $_[0]->[IGNORED_PREFIXES];  };
        -
        -
        -#
        -#   Function: CopyIgnoredPrefixesOf
        -#
        -#   Copies all the ignored prefix settings of the passed <NaturalDocs::Languages::Base> object.
        -#
        -sub CopyIgnoredPrefixesOf #(language)
        -    {
        -    my ($self, $language) = @_;
        -
        -    if ($language->HasIgnoredPrefixes())
        -        {
        -        $self->[IGNORED_PREFIXES] = { };
        -
        -        while (my ($topicType, $prefixes) = each %{$language->[IGNORED_PREFIXES]})
        -            {
        -            $self->[IGNORED_PREFIXES]->{$topicType} = [ @$prefixes ];
        -            };
        -        };
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Parsing Functions
        -
        -
        -#
        -#   Function: ParseFile
        -#
        -#   Parses the passed source file, sending comments acceptable for documentation to <NaturalDocs::Parser->OnComment()>.
        -#   This *must* be defined by a subclass.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The <FileName> of the source file to parse.
        -#       topicList - A reference to the list of <NaturalDocs::Parser::ParsedTopics> being built by the file.
        -#
        -#   Returns:
        -#
        -#       The array ( autoTopics, scopeRecord ).
        -#
        -#       autoTopics - An arrayref of automatically generated <NaturalDocs::Parser::ParsedTopics> from the file, or undef if none.
        -#       scopeRecord - An arrayref of <NaturalDocs::Languages::Advanced::ScopeChanges>, or undef if none.
        -#
        -
        -
        -#
        -#   Function: ParsePrototype
        -#
        -#   Parses the prototype and returns it as a <NaturalDocs::Languages::Prototype> object.
        -#
        -#   Parameters:
        -#
        -#       type - The <TopicType>.
        -#       prototype - The text prototype.
        -#
        -#   Returns:
        -#
        -#       A <NaturalDocs::Languages::Prototype> object.
        -#
        -sub ParsePrototype #(type, prototype)
        -    {
        -    my ($self, $type, $prototype) = @_;
        -
        -    my $isClass = NaturalDocs::Topics->TypeInfo($type)->ClassHierarchy();
        -
        -    if ($prototype !~ /\(.*[^ ].*\)/ && (!$isClass || $prototype !~ /\{.*[^ ].*\}/))
        -        {
        -        my $object = NaturalDocs::Languages::Prototype->New($prototype);
        -        return $object;
        -        };
        -
        -
        -    # Parse the parameters out of the prototype.
        -
        -    my @tokens = $prototype =~ /([^\(\)\[\]\{\}\<\>\'\"\,\;]+|.)/g;
        -
        -    my $parameter;
        -    my @parameterLines;
        -
        -    my @symbolStack;
        -    my $finishedParameters;
        -
        -    my ($beforeParameters, $afterParameters);
        -
        -    foreach my $token (@tokens)
        -        {
        -        if ($finishedParameters)
        -            {  $afterParameters .= $token;  }
        -
        -        elsif ($symbolStack[-1] eq '\'' || $symbolStack[-1] eq '"')
        -            {
        -            if ($symbolStack[0] eq '(' || ($isClass && $symbolStack[0] eq '{'))
        -                {  $parameter .= $token;  }
        -            else
        -                {  $beforeParameters .= $token;  };
        -
        -            if ($token eq $symbolStack[-1])
        -                {  pop @symbolStack;  };
        -            }
        -
        -        elsif ($token =~ /^[\(\[\{\<\'\"]$/)
        -            {
        -            if ($symbolStack[0] eq '(' || ($isClass && $symbolStack[0] eq '{'))
        -                {  $parameter .= $token;   }
        -            else
        -                {  $beforeParameters .= $token;  };
        -
        -            push @symbolStack, $token;
        -            }
        -
        -        elsif ( ($token eq ')' && $symbolStack[-1] eq '(') ||
        -                 ($token eq ']' && $symbolStack[-1] eq '[') ||
        -                 ($token eq '}' && $symbolStack[-1] eq '{') ||
        -                 ($token eq '>' && $symbolStack[-1] eq '<') )
        -            {
        -            if ($symbolStack[0] eq '(')
        -                {
        -                if ($token eq ')' && scalar @symbolStack == 1)
        -                    {
        -                    if ($parameter ne ' ')
        -                        {  push @parameterLines, $parameter;  };
        -
        -                    $finishedParameters = 1;
        -                    $afterParameters .= $token;
        -                    }
        -                else
        -                    {  $parameter .= $token;  };
        -                }
        -            elsif ($isClass && $symbolStack[0] eq '{')
        -                {
        -                if ($token eq '}' && scalar @symbolStack == 1)
        -                    {
        -                    if ($parameter ne ' ')
        -                        {  push @parameterLines, $parameter;  };
        -
        -                    $finishedParameters = 1;
        -                    $afterParameters .= $token;
        -                    }
        -                else
        -                    {  $parameter .= $token;  };
        -                }
        -            else
        -                {
        -                $beforeParameters .= $token;
        -                };
        -
        -            pop @symbolStack;
        -            }
        -
        -        elsif ($token eq ',' || $token eq ';')
        -            {
        -            if ($symbolStack[0] eq '(' || ($isClass && $symbolStack[0] eq '{'))
        -                {
        -                if (scalar @symbolStack == 1)
        -                    {
        -                    push @parameterLines, $parameter . $token;
        -                    $parameter = undef;
        -                    }
        -                else
        -                    {
        -                    $parameter .= $token;
        -                    };
        -                }
        -            else
        -                {
        -                $beforeParameters .= $token;
        -                };
        -            }
        -
        -        else
        -            {
        -            if ($symbolStack[0] eq '(' || ($isClass && $symbolStack[0] eq '{'))
        -                {  $parameter .= $token;  }
        -            else
        -                {  $beforeParameters .= $token;  };
        -            };
        -        };
        -
        -    foreach my $part (\$beforeParameters, \$afterParameters)
        -        {
        -        $$part =~ s/^ //;
        -        $$part =~ s/ $//;
        -        };
        -
        -    my $prototypeObject = NaturalDocs::Languages::Prototype->New($beforeParameters, $afterParameters);
        -
        -
        -    # Parse the actual parameters.
        -
        -    foreach my $parameterLine (@parameterLines)
        -        {
        -        $prototypeObject->AddParameter( $self->ParseParameterLine($parameterLine) );
        -        };
        -
        -    return $prototypeObject;
        -    };
        -
        -
        -#
        -#   Function: ParseParameterLine
        -#
        -#   Parses a prototype parameter line and returns it as a <NaturalDocs::Languages::Prototype::Parameter> object.
        -#
        -#   This vesion assumes a C++ style line.  If you need a Pascal style line, override this function to forward to
        -#   <ParsePascalParameterLine()>.
        -#
        -#   > Function(parameter, type parameter, type parameter = value);
        -#
        -sub ParseParameterLine #(line)
        -    {
        -    my ($self, $line) = @_;
        -
        -    $line =~ s/^ //;
        -    $line =~ s/ $//;
        -
        -    my @tokens = $line =~ /([^ \(\)\{\}\[\]\<\>\'\"\=]+|.)/g;
        -
        -    my @symbolStack;
        -    my @parameterWords = ( undef );
        -    my ($defaultValue, $defaultValuePrefix, $inDefaultValue);
        -
        -    foreach my $token (@tokens)
        -        {
        -        if ($inDefaultValue)
        -            {  $defaultValue .= $token;  }
        -
        -        elsif ($symbolStack[-1] eq '\'' || $symbolStack[-1] eq '"')
        -            {
        -            $parameterWords[-1] .= $token;
        -
        -            if ($token eq $symbolStack[-1])
        -                {  pop @symbolStack;  };
        -            }
        -
        -        elsif ($token =~ /^[\(\[\{\<\'\"]$/)
        -            {
        -            push @symbolStack, $token;
        -            $parameterWords[-1] .= $token;
        -            }
        -
        -        elsif ( ($token eq ')' && $symbolStack[-1] eq '(') ||
        -                 ($token eq ']' && $symbolStack[-1] eq '[') ||
        -                 ($token eq '}' && $symbolStack[-1] eq '{') ||
        -                 ($token eq '>' && $symbolStack[-1] eq '<') )
        -            {
        -            pop @symbolStack;
        -            $parameterWords[-1] .= $token;
        -            }
        -
        -        elsif ($token eq ' ')
        -            {
        -            if (!scalar @symbolStack)
        -                {  push @parameterWords, undef;  }
        -            else
        -                {  $parameterWords[-1] .= $token;  };
        -            }
        -
        -        elsif ($token eq '=')
        -            {
        -            if (!scalar @symbolStack)
        -                {
        -                $defaultValuePrefix = $token;
        -                $inDefaultValue = 1;
        -                }
        -            else
        -                {  $parameterWords[-1] .= $token;  };
        -            }
        -
        -        else
        -            {
        -            $parameterWords[-1] .= $token;
        -            };
        -        };
        -
        -    my ($name, $namePrefix, $type, $typePrefix);
        -
        -    if (!$parameterWords[-1])
        -        {  pop @parameterWords;  };
        -
        -    $name = pop @parameterWords;
        -
        -    if ($parameterWords[-1]=~ /([\*\&]+)$/)
        -        {
        -        $namePrefix = $1;
        -        $parameterWords[-1] = substr($parameterWords[-1], 0, 0 - length($namePrefix));
        -        $parameterWords[-1] =~ s/ $//;
        -
        -        if (!$parameterWords[-1])
        -            {  pop @parameterWords;  };
        -        }
        -    elsif ($name =~ /^([\*\&]+)/)
        -        {
        -        $namePrefix = $1;
        -        $name = substr($name, length($namePrefix));
        -        $name =~ s/^ //;
        -        };
        -
        -    $type = pop @parameterWords;
        -    $typePrefix = join(' ', @parameterWords);
        -
        -    if ($typePrefix)
        -        {  $typePrefix .= ' ';  };
        -
        -    if ($type =~ /^([a-z0-9_\:\.]+(?:\.|\:\:))[a-z0-9_]/i)
        -        {
        -        my $attachedTypePrefix = $1;
        -
        -        $typePrefix .= $attachedTypePrefix;
        -        $type = substr($type, length($attachedTypePrefix));
        -        };
        -
        -    $defaultValue =~ s/ $//;
        -
        -    return NaturalDocs::Languages::Prototype::Parameter->New($type, $typePrefix, $name, $namePrefix,
        -                                                                                             $defaultValue, $defaultValuePrefix);
        -    };
        -
        -
        -#
        -#   Function: ParsePascalParameterLine
        -#
        -#   Parses a Pascal-like prototype parameter line and returns it as a <NaturalDocs::Languages::Prototype::Parameter> object.
        -#   Pascal lines are as follows:
        -#
        -#   > Function (name: type; name, name: type := value)
        -#
        -#   Also supports ActionScript lines
        -#
        -#   > Function (name: type, name, name: type = value)
        -#
        -sub ParsePascalParameterLine #(line)
        -    {
        -    my ($self, $line) = @_;
        -
        -    $line =~ s/^ //;
        -    $line =~ s/ $//;
        -
        -    my @tokens = $line =~ /([^\(\)\{\}\[\]\<\>\'\"\=\:]+|\:\=|.)/g;
        -    my ($type, $name, $defaultValue, $defaultValuePrefix, $afterName, $afterDefaultValue);
        -    my @symbolStack;
        -
        -    foreach my $token (@tokens)
        -        {
        -        if ($afterDefaultValue)
        -            {  $defaultValue .= $token;  }
        -
        -        elsif ($symbolStack[-1] eq '\'' || $symbolStack[-1] eq '"')
        -            {
        -            if ($afterName)
        -                {  $type .= $token;  }
        -            else
        -                {  $name .= $token;  };
        -
        -            if ($token eq $symbolStack[-1])
        -                {  pop @symbolStack;  };
        -            }
        -
        -        elsif ($token =~ /^[\(\[\{\<\'\"]$/)
        -            {
        -            push @symbolStack, $token;
        -
        -            if ($afterName)
        -                {  $type .= $token;  }
        -            else
        -                {  $name .= $token;  };
        -            }
        -
        -        elsif ( ($token eq ')' && $symbolStack[-1] eq '(') ||
        -                 ($token eq ']' && $symbolStack[-1] eq '[') ||
        -                 ($token eq '}' && $symbolStack[-1] eq '{') ||
        -                 ($token eq '>' && $symbolStack[-1] eq '<') )
        -            {
        -            pop @symbolStack;
        -
        -            if ($afterName)
        -                {  $type .= $token;  }
        -            else
        -                {  $name .= $token;  };
        -            }
        -
        -        elsif ($afterName)
        -            {
        -            if (($token eq ':=' || $token eq '=') && !scalar @symbolStack)
        -                {
        -                $defaultValuePrefix = $token;
        -                $afterDefaultValue = 1;
        -                }
        -            else
        -                {  $type .= $token;  };
        -            }
        -
        -        elsif ($token eq ':' && !scalar @symbolStack)
        -            {
        -            $name .= $token;
        -            $afterName = 1;
        -            }
        -
        -        else
        -            {  $name .= $token;  };
        -        };
        -
        -    foreach my $part (\$type, \$name, \$defaultValue)
        -        {
        -        $$part =~ s/^ //;
        -        $$part =~ s/ $//;
        -        };
        -
        -    return NaturalDocs::Languages::Prototype::Parameter->New($type, undef, $name, undef, $defaultValue, $defaultValuePrefix);
        -    };
        -
        -
        -#
        -#   Function: TypeBeforeParameter
        -#
        -#   Returns whether the type appears before the parameter in prototypes.
        -#
        -#   For example, it does in C++
        -#   > void Function (int a, int b)
        -#
        -#   but does not in Pascal
        -#   > function Function (a: int; b, c: int)
        -#
        -sub TypeBeforeParameter
        -    {
        -    return 1;
        -    };
        -
        -
        -
        -#
        -#   Function: IgnoredPrefixLength
        -#
        -#   Returns the length of the prefix that should be ignored in the index, or zero if none.
        -#
        -#   Parameters:
        -#
        -#       name - The name of the symbol.
        -#       type  - The symbol's <TopicType>.
        -#
        -#   Returns:
        -#
        -#       The length of the prefix to ignore, or zero if none.
        -#
        -sub IgnoredPrefixLength #(name, type)
        -    {
        -    my ($self, $name, $type) = @_;
        -
        -    foreach my $prefixes ($self->IgnoredPrefixesFor($type), $self->IgnoredPrefixesFor(::TOPIC_GENERAL()))
        -        {
        -        if (defined $prefixes)
        -            {
        -            foreach my $prefix (@$prefixes)
        -                {
        -                if (substr($name, 0, length($prefix)) eq $prefix)
        -                    {  return length($prefix);  };
        -                };
        -            };
        -        };
        -
        -    return 0;
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -
        -#
        -#   Function: StripOpeningSymbols
        -#
        -#   Determines if the line starts with any of the passed symbols, and if so, replaces it with spaces.  This only happens
        -#   if the only thing before it on the line is whitespace.
        -#
        -#   Parameters:
        -#
        -#       lineRef - A reference to the line to check.
        -#       symbols - An arrayref of the symbols to check for.
        -#
        -#   Returns:
        -#
        -#       If the line starts with any of the passed comment symbols, it will replace it in the line with spaces and return the symbol.
        -#       If the line doesn't, it will leave the line alone and return undef.
        -#
        -sub StripOpeningSymbols #(lineRef, symbols)
        -    {
        -    my ($self, $lineRef, $symbols) = @_;
        -
        -    if (!defined $symbols)
        -        {  return undef;  };
        -
        -    my ($index, $symbol) = ::FindFirstSymbol($$lineRef, $symbols);
        -
        -    if ($index != -1 && substr($$lineRef, 0, $index) =~ /^[ \t]*$/)
        -        {
        -        return substr($$lineRef, $index, length($symbol), ' ' x length($symbol));
        -        };
        -
        -    return undef;
        -    };
        -
        -
        -#
        -#   Function: StripOpeningJavaDocSymbols
        -#
        -#   Determines if the line starts with any of the passed symbols, and if so, replaces it with spaces.  This only happens
        -#   if the only thing before it on the line is whitespace and the next character after it is whitespace or the end of the line.
        -#
        -#   Parameters:
        -#
        -#       lineRef - A reference to the line to check.
        -#       symbols - An arrayref of the symbols to check for.
        -#
        -#   Returns:
        -#
        -#       If the line starts with any of the passed comment symbols, it will replace it in the line with spaces and return the symbol.
        -#       If the line doesn't, it will leave the line alone and return undef.
        -#
        -sub StripOpeningJavaDocSymbols #(lineRef, symbols)
        -    {
        -    my ($self, $lineRef, $symbols) = @_;
        -
        -    if (!defined $symbols)
        -        {  return undef;  };
        -
        -    my ($index, $symbol) = ::FindFirstSymbol($$lineRef, $symbols);
        -
        -    if ($index != -1 && substr($$lineRef, 0, $index) =~ /^[ \t]*$/ && substr($$lineRef, $index + length($symbol), 1) =~ /^[ \t]?$/)
        -        {
        -        return substr($$lineRef, $index, length($symbol), ' ' x length($symbol));
        -        };
        -
        -    return undef;
        -    };
        -
        -
        -#
        -#   Function: StripOpeningBlockSymbols
        -#
        -#   Determines if the line starts with any of the opening symbols in the passed symbol pairs, and if so, replaces it with spaces.
        -#   This only happens if the only thing before it on the line is whitespace.
        -#
        -#   Parameters:
        -#
        -#       lineRef - A reference to the line to check.
        -#       symbolPairs - An arrayref of the symbol pairs to check for.  Pairs are specified as two consecutive array entries, with the
        -#                            opening symbol first.
        -#
        -#   Returns:
        -#
        -#       If the line starts with any of the opening symbols, it will replace it in the line with spaces and return the closing symbol.
        -#       If the line doesn't, it will leave the line alone and return undef.
        -#
        -sub StripOpeningBlockSymbols #(lineRef, symbolPairs)
        -    {
        -    my ($self, $lineRef, $symbolPairs) = @_;
        -
        -    if (!defined $symbolPairs)
        -        {  return undef;  };
        -
        -    for (my $i = 0; $i < scalar @$symbolPairs; $i += 2)
        -        {
        -        my $index = index($$lineRef, $symbolPairs->[$i]);
        -
        -        if ($index != -1 && substr($$lineRef, 0, $index) =~ /^[ \t]*$/)
        -            {
        -            substr($$lineRef, $index, length($symbolPairs->[$i]), ' ' x length($symbolPairs->[$i]));
        -            return $symbolPairs->[$i + 1];
        -            };
        -        };
        -
        -    return undef;
        -    };
        -
        -
        -#
        -#   Function: StripOpeningJavaDocBlockSymbols
        -#
        -#   Determines if the line starts with any of the opening symbols in the passed symbol pairs, and if so, replaces it with spaces.
        -#   This only happens if the only thing before it on the line is whitespace and the next character is whitespace or the end of the line.
        -#
        -#   Parameters:
        -#
        -#       lineRef - A reference to the line to check.
        -#       symbolPairs - An arrayref of the symbol pairs to check for.  Pairs are specified as two consecutive array entries, with the
        -#                            opening symbol first.
        -#
        -#   Returns:
        -#
        -#       If the line starts with any of the opening symbols, it will replace it in the line with spaces and return the closing symbol.
        -#       If the line doesn't, it will leave the line alone and return undef.
        -#
        -sub StripOpeningJavaDocBlockSymbols #(lineRef, symbolPairs)
        -    {
        -    my ($self, $lineRef, $symbolPairs) = @_;
        -
        -    if (!defined $symbolPairs)
        -        {  return undef;  };
        -
        -    for (my $i = 0; $i < scalar @$symbolPairs; $i += 2)
        -        {
        -        my $index = index($$lineRef, $symbolPairs->[$i]);
        -
        -        if ($index != -1 && substr($$lineRef, 0, $index) =~ /^[ \t]*$/ &&
        -            substr($$lineRef, $index + length($symbolPairs->[$i]), 1) =~ /^[ \t]?$/)
        -            {
        -            substr($$lineRef, $index, length($symbolPairs->[$i]), ' ' x length($symbolPairs->[$i]));
        -            return $symbolPairs->[$i + 1];
        -            };
        -        };
        -
        -    return undef;
        -    };
        -
        -
        -#
        -#   Function: StripClosingSymbol
        -#
        -#   Determines if the line contains a symbol, and if so, truncates it just before the symbol.
        -#
        -#   Parameters:
        -#
        -#       lineRef - A reference to the line to check.
        -#       symbol - The symbol to check for.
        -#
        -#   Returns:
        -#
        -#       The remainder of the line, or undef if the symbol was not found.
        -#
        -sub StripClosingSymbol #(lineRef, symbol)
        -    {
        -    my ($self, $lineRef, $symbol) = @_;
        -
        -    my $index = index($$lineRef, $symbol);
        -
        -    if ($index != -1)
        -        {
        -        my $lineRemainder = substr($$lineRef, $index + length($symbol));
        -        $$lineRef = substr($$lineRef, 0, $index);
        -
        -        return $lineRemainder;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: NormalizePrototype
        -#
        -#   Normalizes a prototype.  Specifically, condenses spaces, tabs, and line breaks into single spaces and removes leading and
        -#   trailing ones.
        -#
        -#   Parameters:
        -#
        -#       prototype - The original prototype string.
        -#
        -#   Returns:
        -#
        -#       The normalized prototype.
        -#
        -sub NormalizePrototype #(prototype)
        -    {
        -    my ($self, $prototype) = @_;
        -
        -    $prototype =~ tr/ \t\r\n/ /s;
        -    $prototype =~ s/^ //;
        -    $prototype =~ s/ $//;
        -
        -    return $prototype;
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages/CSharp.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages/CSharp.pm
        deleted file mode 100644
        index 13a0c94fb..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages/CSharp.pm
        +++ /dev/null
        @@ -1,1552 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Languages::CSharp
        -#
        -###############################################################################
        -#
        -#   A subclass to handle the language variations of C#.
        -#
        -#
        -#   Topic: Language Support
        -#
        -#       Supported:
        -#
        -#       - Classes
        -#       - Namespaces (no topic generated)
        -#       - Functions
        -#       - Constructors and Destructors
        -#       - Properties
        -#       - Indexers
        -#       - Operators
        -#       - Delegates
        -#       - Variables
        -#       - Constants
        -#       - Events
        -#       - Enums
        -#
        -#       Not supported yet:
        -#
        -#       - Autodocumenting enum members
        -#       - Using alias
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Languages::CSharp;
        -
        -use base 'NaturalDocs::Languages::Advanced';
        -
        -
        -###############################################################################
        -# Group: Package Variables
        -
        -#
        -#   hash: classKeywords
        -#   An existence hash of all the acceptable class keywords.  The keys are in all lowercase.
        -#
        -my %classKeywords = ( 'class' => 1,
        -                                    'struct' => 1,
        -                                    'interface' => 1 );
        -
        -#
        -#   hash: classModifiers
        -#   An existence hash of all the acceptable class modifiers.  The keys are in all lowercase.
        -#
        -my %classModifiers = ( 'new' => 1,
        -                                   'public' => 1,
        -                                   'protected' => 1,
        -                                   'internal' => 1,
        -                                   'private' => 1,
        -                                   'abstract' => 1,
        -                                   'sealed' => 1,
        -                                   'unsafe' => 1,
        -                                   'static' => 1,
        -                                   'partial' => 1 );
        -
        -#
        -#   hash: functionModifiers
        -#   An existence hash of all the acceptable function modifiers.  Also applies to properties.  Also encompasses those for operators
        -#   and indexers, but have more than are valid for them.  The keys are in all lowercase.
        -#
        -my %functionModifiers = ( 'new' => 1,
        -                                       'public' => 1,
        -                                       'protected' => 1,
        -                                       'internal' => 1,
        -                                       'private' => 1,
        -                                       'static' => 1,
        -                                       'virtual' => 1,
        -                                       'sealed' => 1,
        -                                       'override' => 1,
        -                                       'abstract' => 1,
        -                                       'extern' => 1,
        -                                       'unsafe' => 1 );
        -
        -#
        -#   hash: variableModifiers
        -#   An existence hash of all the acceptable variable modifiers.  The keys are in all lowercase.
        -#
        -my %variableModifiers = ( 'new' => 1,
        -                                       'public' => 1,
        -                                       'protected' => 1,
        -                                       'internal' => 1,
        -                                       'private' => 1,
        -                                       'static' => 1,
        -                                       'readonly' => 1,
        -                                       'volatile' => 1,
        -                                       'unsafe' => 1 );
        -
        -#
        -#   hash: enumTypes
        -#   An existence hash of all the possible enum types.  The keys are in all lowercase.
        -#
        -my %enumTypes = ( 'sbyte' => 1,
        -                             'byte' => 1,
        -                             'short' => 1,
        -                             'ushort' => 1,
        -                             'int' => 1,
        -                             'uint' => 1,
        -                             'long' => 1,
        -                             'ulong' => 1 );
        -
        -#
        -#   hash: impossibleTypeWords
        -#   An existence hash of all the reserved words that cannot be in a type.  This includes 'enum' and all modifiers.  The keys are in
        -#   all lowercase.
        -#
        -my %impossibleTypeWords = ( 'abstract' => 1, 'as' => 1, 'base' => 1, 'break' => 1, 'case' => 1, 'catch' => 1,
        -                                              'checked' => 1, 'class' => 1, 'const' => 1, 'continue' => 1, 'default' => 1, 'delegate' => 1,
        -                                              'do' => 1, 'else' => 1, 'enum' => 1, 'event' => 1, 'explicit' => 1, 'extern' => 1,
        -                                              'false' => 1, 'finally' => 1, 'fixed' => 1, 'for' => 1, 'foreach' => 1, 'goto' => 1, 'if' => 1,
        -                                              'implicit' => 1, 'in' => 1, 'interface' => 1, 'internal' => 1, 'is' => 1, 'lock' => 1,
        -                                              'namespace' => 1, 'new' => 1, 'null' => 1, 'operator' => 1, 'out' => 1, 'override' => 1,
        -                                              'params' => 1, 'private' => 1, 'protected' => 1, 'public' => 1, 'readonly' => 1, 'ref' => 1,
        -                                              'return' => 1, 'sealed' => 1, 'sizeof' => 1, 'stackalloc' => 1, 'static' => 1,
        -                                              'struct' => 1, 'switch' => 1, 'this' => 1, 'throw' => 1, 'true' => 1, 'try' => 1, 'typeof' => 1,
        -                                              'unchecked' => 1, 'unsafe' => 1, 'using' => 1, 'virtual' => 1, 'volatile' => 1, 'while' => 1 );
        -# Deleted from the list: object, string, bool, decimal, sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, void
        -
        -
        -
        -###############################################################################
        -# Group: Interface Functions
        -
        -
        -#
        -#   Function: PackageSeparator
        -#   Returns the package separator symbol.
        -#
        -sub PackageSeparator
        -    {  return '.';  };
        -
        -
        -#
        -#   Function: EnumValues
        -#   Returns the <EnumValuesType> that describes how the language handles enums.
        -#
        -sub EnumValues
        -    {  return ::ENUM_UNDER_TYPE();  };
        -
        -
        -#
        -#   Function: ParseFile
        -#
        -#   Parses the passed source file, sending comments acceptable for documentation to <NaturalDocs::Parser->OnComment()>.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The <FileName> to parse.
        -#       topicList - A reference to the list of <NaturalDocs::Parser::ParsedTopics> being built by the file.
        -#
        -#   Returns:
        -#
        -#       The array ( autoTopics, scopeRecord ).
        -#
        -#       autoTopics - An arrayref of automatically generated topics from the file, or undef if none.
        -#       scopeRecord - An arrayref of <NaturalDocs::Languages::Advanced::ScopeChanges>, or undef if none.
        -#
        -sub ParseFile #(sourceFile, topicsList)
        -    {
        -    my ($self, $sourceFile, $topicsList) = @_;
        -
        -    $self->ParseForCommentsAndTokens($sourceFile, [ '//' ], [ '/*', '*/' ], [ '///' ], [ '/**', '*/' ] );
        -
        -    my $tokens = $self->Tokens();
        -    my $index = 0;
        -    my $lineNumber = 1;
        -
        -    while ($index < scalar @$tokens)
        -        {
        -        if ($self->TryToSkipWhitespace(\$index, \$lineNumber) ||
        -            $self->TryToGetNamespace(\$index, \$lineNumber) ||
        -            $self->TryToGetUsing(\$index, \$lineNumber) ||
        -            $self->TryToGetClass(\$index, \$lineNumber) ||
        -            $self->TryToGetFunction(\$index, \$lineNumber) ||
        -            $self->TryToGetOverloadedOperator(\$index, \$lineNumber) ||
        -            $self->TryToGetVariable(\$index, \$lineNumber) ||
        -            $self->TryToGetEnum(\$index, \$lineNumber) )
        -            {
        -            # The functions above will handle everything.
        -            }
        -
        -        elsif ($tokens->[$index] eq '{')
        -            {
        -            $self->StartScope('}', $lineNumber, undef, undef, undef);
        -            $index++;
        -            }
        -
        -        elsif ($tokens->[$index] eq '}')
        -            {
        -            if ($self->ClosingScopeSymbol() eq '}')
        -                {  $self->EndScope($lineNumber);  };
        -
        -            $index++;
        -            }
        -
        -        else
        -            {
        -            $self->SkipRestOfStatement(\$index, \$lineNumber);
        -            };
        -        };
        -
        -
        -    # Don't need to keep these around.
        -    $self->ClearTokens();
        -
        -
        -    my $autoTopics = $self->AutoTopics();
        -
        -    my $scopeRecord = $self->ScopeRecord();
        -    if (defined $scopeRecord && !scalar @$scopeRecord)
        -        {  $scopeRecord = undef;  };
        -
        -    return ( $autoTopics, $scopeRecord );
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Statement Parsing Functions
        -# All functions here assume that the current position is at the beginning of a statement.
        -#
        -# Note for developers: I am well aware that the code in these functions do not check if we're past the end of the tokens as
        -# often as it should.  We're making use of the fact that Perl will always return undef in these cases to keep the code simpler.
        -
        -
        -#
        -#   Function: TryToGetNamespace
        -#
        -#   Determines whether the position is at a namespace declaration statement, and if so, adjusts the scope, skips it, and returns
        -#   true.
        -#
        -#   Why no topic?:
        -#
        -#       The main reason we don't create a Natural Docs topic for a namespace is because in order to declare class A.B.C in C#,
        -#       you must do this:
        -#
        -#       > namespace A.B
        -#       >    {
        -#       >    class C
        -#       >        { ... }
        -#       >    }
        -#
        -#       That would result in a namespace topic whose only purpose is really to qualify C.  It would take the default page title, and
        -#       thus the default menu title.  So if you have files for A.B.X, A.B.Y, and A.B.Z, they all will appear as A.B on the menu.
        -#
        -#       If something actually appears in the namespace besides a class, it will be handled by
        -#       <NaturalDocs::Parser->AddPackageDelineators()>.  That function will add a package topic to correct the scope.
        -#
        -#       If the user actually documented it, it will still appear because of the manual topic.
        -#
        -sub TryToGetNamespace #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if (lc($tokens->[$$indexRef]) ne 'namespace')
        -        {  return undef;  };
        -
        -    my $index = $$indexRef + 1;
        -    my $lineNumber = $$lineNumberRef;
        -
        -    if (!$self->TryToSkipWhitespace(\$index, \$lineNumber))
        -        {  return undef;  };
        -
        -    my $name;
        -
        -    while ($tokens->[$index] =~ /^[a-z_\.\@]/i)
        -        {
        -        $name .= $tokens->[$index];
        -        $index++;
        -        };
        -
        -    if (!defined $name)
        -        {  return undef;  };
        -
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -    if ($tokens->[$index] ne '{')
        -        {  return undef;  };
        -
        -    $index++;
        -
        -
        -    # We found a valid one if we made it this far.
        -
        -    my $autoTopic = NaturalDocs::Parser::ParsedTopic->New(::TOPIC_CLASS(), $name,
        -                                                                                         $self->CurrentScope(), $self->CurrentUsing(),
        -                                                                                         undef,
        -                                                                                         undef, undef, $$lineNumberRef);
        -
        -    # We don't add an auto-topic for namespaces.  See the function documentation above.
        -
        -    NaturalDocs::Parser->OnClass($autoTopic->Package());
        -
        -    $self->StartScope('}', $lineNumber, $autoTopic->Package());
        -
        -    $$indexRef = $index;
        -    $$lineNumberRef = $lineNumber;
        -
        -    return 1;
        -    };
        -
        -
        -#
        -#   Function: TryToGetClass
        -#
        -#   Determines whether the position is at a class declaration statement, and if so, generates a topic for it, skips it, and
        -#   returns true.
        -#
        -#   Supported Syntaxes:
        -#
        -#       - Classes
        -#       - Structs
        -#       - Interfaces
        -#
        -sub TryToGetClass #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $index = $$indexRef;
        -    my $lineNumber = $$lineNumberRef;
        -
        -    my $startIndex = $index;
        -    my $startLine = $lineNumber;
        -    my $needsPrototype = 0;
        -
        -    if ($self->TryToSkipAttributes(\$index, \$lineNumber))
        -        {  $self->TryToSkipWhitespace(\$index, \$lineNumber);  }
        -
        -    my @modifiers;
        -
        -    while ($tokens->[$index] =~ /^[a-z]/i &&
        -              !exists $classKeywords{lc($tokens->[$index])} &&
        -              exists $classModifiers{lc($tokens->[$index])} )
        -        {
        -        push @modifiers, lc($tokens->[$index]);
        -        $index++;
        -
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        };
        -
        -    if (!exists $classKeywords{lc($tokens->[$index])})
        -        {  return undef;  };
        -
        -    my $lcClassKeyword = lc($tokens->[$index]);
        -
        -    $index++;
        -
        -    if (!$self->TryToSkipWhitespace(\$index, \$lineNumber))
        -        {  return undef;  };
        -
        -    my $name;
        -
        -    while ($tokens->[$index] =~ /^[a-z_\@]/i)
        -        {
        -        $name .= $tokens->[$index];
        -        $index++;
        -        };
        -
        -    if (!defined $name)
        -        {  return undef;  };
        -
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -	if ($self->TryToSkipTemplateSpec(\$index, \$lineNumber))
        -		{
        -		$needsPrototype = 1;
        -		$self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -		if ($self->TryToSkipWhereClauses(\$index, \$lineNumber))
        -			{  $self->TryToSkipWhitespace(\$index, \$lineNumber);  }
        -		}
        -
        -    my @parents;
        -
        -    if ($tokens->[$index] eq ':')
        -        {
        -        my $inheritsTemplates;
        -
        -        do
        -            {
        -            $index++;
        -
        -            $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -            my $parentName;
        -
        -            while ($tokens->[$index] =~ /^[a-z_\.\@]/i)
        -                {
        -                $parentName .= $tokens->[$index];
        -                $index++;
        -                };
        -
        -            if (!defined $parentName)
        -                {  return undef;  };
        -
        -            push @parents, NaturalDocs::SymbolString->FromText($parentName);
        -
        -            $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -            if ($self->TryToSkipTemplateSpec(\$index, \$lineNumber))
        -            	{
        -            	$inheritsTemplates = 1;
        -            	$needsPrototype = 1;
        -            	$self->TryToSkipWhitespace(\$index, \$lineNumber);
        -            	}
        -            }
        -        while ($tokens->[$index] eq ',');
        -
        -        if ($inheritsTemplates)
        -        	{
        -        	if ($self->TryToSkipWhereClauses(\$index, \$lineNumber))
        -        		{  $self->TryToSkipWhitespace(\$index, \$lineNumber);  }
        -        	}
        -        };
        -
        -    if ($tokens->[$index] ne '{')
        -        {  return undef;  };
        -
        -
        -    # If we made it this far, we have a valid class declaration.
        -
        -    my @scopeIdentifiers = NaturalDocs::SymbolString->IdentifiersOf($self->CurrentScope());
        -    $name = join('.', @scopeIdentifiers, $name);
        -
        -    my $topicType;
        -
        -    if ($lcClassKeyword eq 'interface')
        -        {  $topicType = ::TOPIC_INTERFACE();  }
        -    else
        -        {  $topicType = ::TOPIC_CLASS();  };
        -
        -    my $prototype;
        -
        -    if ($needsPrototype)
        -            {
        -            $prototype = $self->CreateString($startIndex, $index);
        -            }
        -
        -    my $autoTopic = NaturalDocs::Parser::ParsedTopic->New($topicType, $name,
        -                                                                                         undef, $self->CurrentUsing(),
        -                                                                                         $prototype,
        -                                                                                         undef, undef, $$lineNumberRef);
        -
        -    $self->AddAutoTopic($autoTopic);
        -    NaturalDocs::Parser->OnClass($autoTopic->Package());
        -
        -    foreach my $parent (@parents)
        -        {
        -        NaturalDocs::Parser->OnClassParent($autoTopic->Package(), $parent, $self->CurrentScope(), undef,
        -                                                               ::RESOLVE_RELATIVE());
        -        };
        -
        -    $self->StartScope('}', $lineNumber, $autoTopic->Package());
        -
        -    $index++;
        -
        -    $$indexRef = $index;
        -    $$lineNumberRef = $lineNumber;
        -
        -    return 1;
        -    };
        -
        -
        -#
        -#   Function: TryToGetUsing
        -#
        -#   Determines whether the position is at a using statement, and if so, adds it to the current scope, skips it, and returns
        -#        true.
        -#
        -#        Supported:
        -#
        -#       - Using
        -#
        -#        Unsupported:
        -#
        -#                - Using with alias
        -#
        -sub TryToGetUsing #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $index = $$indexRef;
        -    my $lineNumber = $$lineNumberRef;
        -
        -    if (lc($tokens->[$index]) ne 'using')
        -        {  return undef;  };
        -
        -    $index++;
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -    my $name;
        -
        -    while ($tokens->[$index] =~ /^[a-z_\@\.]/i)
        -        {
        -        $name .= $tokens->[$index];
        -        $index++;
        -        };
        -
        -    if ($tokens->[$index] ne ';' ||
        -                !defined $name)
        -        {  return undef;  };
        -
        -    $index++;
        -
        -
        -    $self->AddUsing( NaturalDocs::SymbolString->FromText($name) );
        -
        -    $$indexRef = $index;
        -    $$lineNumberRef = $lineNumber;
        -
        -    return 1;
        -    };
        -
        -
        -
        -#
        -#   Function: TryToGetFunction
        -#
        -#   Determines if the position is on a function declaration, and if so, generates a topic for it, skips it, and returns true.
        -#
        -#   Supported Syntaxes:
        -#
        -#       - Functions
        -#       - Constructors
        -#       - Destructors
        -#       - Properties
        -#       - Indexers
        -#       - Delegates
        -#       - Events
        -#
        -sub TryToGetFunction #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $index = $$indexRef;
        -    my $lineNumber = $$lineNumberRef;
        -
        -    if ($self->TryToSkipAttributes(\$index, \$lineNumber))
        -        {  $self->TryToSkipWhitespace(\$index, \$lineNumber);  };
        -
        -    my $startIndex = $index;
        -    my $startLine = $lineNumber;
        -
        -    my @modifiers;
        -
        -    while ($tokens->[$index] =~ /^[a-z]/i &&
        -              exists $functionModifiers{lc($tokens->[$index])} )
        -        {
        -        push @modifiers, lc($tokens->[$index]);
        -        $index++;
        -
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        };
        -
        -    my $isDelegate;
        -    my $isEvent;
        -
        -    if (lc($tokens->[$index]) eq 'delegate')
        -        {
        -        $isDelegate = 1;
        -        $index++;
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        }
        -    elsif (lc($tokens->[$index]) eq 'event')
        -        {
        -        $isEvent = 1;
        -        $index++;
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        };
        -
        -    my $returnType = $self->TryToGetType(\$index, \$lineNumber);
        -
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -    my $name;
        -    my $lastNameWord;
        -    my $hasTemplates;
        -
        -    while ($tokens->[$index] =~ /^[a-z\_\@\.\~]/i)
        -        {
        -        $name .= $tokens->[$index];
        -        $lastNameWord = $tokens->[$index];
        -        $index++;
        -
        -        # For explicit generic interface definitions, such as
        -        # IDObjectType System.Collections.Generic.IEnumerator<IDObjectType>.Current
        -        # or templated functions.
        -
        -        if ($self->TryToSkipTemplateSpec(\$index, \$lineNumber))
        -        	{
        -        	$hasTemplates = 1;
        -        	$self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        	}
        -        };
        -
        -    if (!defined $name)
        -        {
        -        # Constructors and destructors don't have return types.  It's possible their names were mistaken for the return type.
        -        if (defined $returnType)
        -            {
        -            $name = $returnType;
        -            $returnType = undef;
        -
        -            $name =~ /([a-z0-9_]+)$/i;
        -            $lastNameWord = $1;
        -            }
        -        else
        -            {  return undef;  };
        -        };
        -
        -    # If there's no return type, make sure it's a constructor or destructor.
        -    if (!defined $returnType)
        -        {
        -        my @identifiers = NaturalDocs::SymbolString->IdentifiersOf( $self->CurrentScope() );
        -
        -        if ($lastNameWord ne $identifiers[-1])
        -            {  return undef;  };
        -        };
        -
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -
        -    # Skip the brackets on indexers.
        -    if ($tokens->[$index] eq '[' && lc($lastNameWord) eq 'this')
        -        {
        -        # This should jump the brackets completely.
        -        $self->GenericSkip(\$index, \$lineNumber);
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        $name .= '[]';
        -        };
        -
        -
        -    # Properties, indexers, events with braces
        -
        -    if ($tokens->[$index] eq '{')
        -        {
        -        my $prototype = $self->CreateString($startIndex, $index);
        -
        -        $index++;
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        my ($aWord, $bWord, $hasA, $hasB);
        -
        -        if ($isEvent)
        -            {
        -            $aWord = 'add';
        -            $bWord = 'remove';
        -            }
        -        else
        -            {
        -            $aWord = 'get';
        -            $bWord = 'set';
        -            };
        -
        -        while ($index < scalar @$tokens)
        -            {
        -            if ($self->TryToSkipAttributes(\$index, \$lineNumber))
        -                {  $self->TryToSkipWhitespace(\$index, \$lineNumber);  };
        -
        -            if (lc($tokens->[$index]) eq $aWord)
        -                {  $hasA = 1;  }
        -            elsif (lc($tokens->[$index]) eq $bWord)
        -                {  $hasB = 1;  }
        -            elsif ($tokens->[$index] eq '}')
        -                {
        -                $index++;
        -                last;
        -                };
        -
        -            $self->SkipRestOfStatement(\$index, \$lineNumber);
        -            $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -            };
        -
        -        if ($hasA && $hasB)
        -            {  $prototype .= ' { ' . $aWord . ', ' . $bWord . ' }';  }
        -        elsif ($hasA)
        -            {  $prototype .= ' { ' . $aWord . ' }';  }
        -        elsif ($hasB)
        -            {  $prototype .= ' { ' . $bWord . ' }';  };
        -
        -        $prototype = $self->NormalizePrototype($prototype);
        -
        -        my $topicType = ( $isEvent ? ::TOPIC_EVENT() : ::TOPIC_PROPERTY() );
        -
        -        $self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New($topicType, $name,
        -                                                                                                  $self->CurrentScope(), $self->CurrentUsing(),
        -                                                                                                  $prototype,
        -                                                                                                  undef, undef, $startLine));
        -        }
        -
        -
        -    # Functions, constructors, destructors, delegates.
        -
        -    elsif ($tokens->[$index] eq '(')
        -        {
        -        # This should jump the parenthesis completely.
        -        $self->GenericSkip(\$index, \$lineNumber);
        -		$self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        if ($hasTemplates && $self->TryToSkipWhereClauses(\$index, \$lineNumber))
        -        	{  $self->TryToSkipWhitespace(\$index, \$lineNumber);  }
        -
        -        my $topicType = ( $isDelegate ? ::TOPIC_DELEGATE() : ::TOPIC_FUNCTION() );
        -        my $prototype = $self->NormalizePrototype( $self->CreateString($startIndex, $index) );
        -
        -        $self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New($topicType, $name,
        -                                                                                                  $self->CurrentScope(), $self->CurrentUsing(),
        -                                                                                                  $prototype,
        -                                                                                                  undef, undef, $startLine));
        -
        -        $self->SkipRestOfStatement(\$index, \$lineNumber);
        -        }
        -
        -
        -    # Events without braces
        -
        -    elsif ($isEvent && $tokens->[$index] eq ';')
        -        {
        -        my $prototype = $self->NormalizePrototype( $self->CreateString($startIndex, $index) );
        -
        -        $self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New(::TOPIC_EVENT(), $name,
        -                                                                                                  $self->CurrentScope(), $self->CurrentUsing(),
        -                                                                                                  $prototype,
        -                                                                                                  undef, undef, $startLine));
        -        $index++;
        -        }
        -
        -    else
        -        {  return undef;  };
        -
        -
        -    # We succeeded if we got this far.
        -
        -    $$indexRef = $index;
        -    $$lineNumberRef = $lineNumber;
        -
        -    return 1;
        -    };
        -
        -
        -#
        -#   Function: TryToGetOverloadedOperator
        -#
        -#   Determines if the position is on an operator overload declaration, and if so, generates a topic for it, skips it, and returns true.
        -#
        -sub TryToGetOverloadedOperator #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $index = $$indexRef;
        -    my $lineNumber = $$lineNumberRef;
        -
        -    if ($self->TryToSkipAttributes(\$index, \$lineNumber))
        -        {  $self->TryToSkipWhitespace(\$index, \$lineNumber);  };
        -
        -    my $startIndex = $index;
        -    my $startLine = $lineNumber;
        -
        -    my @modifiers;
        -
        -    while ($tokens->[$index] =~ /^[a-z]/i &&
        -              exists $functionModifiers{lc($tokens->[$index])} )
        -        {
        -        push @modifiers, lc($tokens->[$index]);
        -        $index++;
        -
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        };
        -
        -
        -    my $name;
        -
        -
        -    # Casting operators.
        -
        -    if (lc($tokens->[$index]) eq 'implicit' || lc($tokens->[$index]) eq 'explicit')
        -        {
        -        $index++;
        -
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        if (lc($tokens->[$index]) ne 'operator')
        -            {  return undef;  };
        -
        -        $index++;
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        $name = $self->TryToGetType(\$index, \$lineNumber);
        -
        -        if (!defined $name)
        -            {  return undef;  };
        -        }
        -
        -
        -    # Symbol operators.
        -
        -    else
        -        {
        -        if (!$self->TryToGetType(\$index, \$lineNumber))
        -            {  return undef;  };
        -
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        if (lc($tokens->[$index]) ne 'operator')
        -            {  return undef;  };
        -
        -        $index++;
        -
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        if (lc($tokens->[$index]) eq 'true' || lc($tokens->[$index]) eq 'false')
        -            {
        -            $name = $tokens->[$index];
        -            $index++;
        -            }
        -        else
        -            {
        -            while ($tokens->[$index] =~ /^[\+\-\!\~\*\/\%\&\|\^\<\>\=]$/)
        -                {
        -                $name .= $tokens->[$index];
        -                $index++;
        -                };
        -            };
        -        };
        -
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -    if ($tokens->[$index] ne '(')
        -        {  return undef;  };
        -
        -    # This should skip the parenthesis completely.
        -    $self->GenericSkip(\$index, \$lineNumber);
        -
        -    my $prototype = $self->NormalizePrototype( $self->CreateString($startIndex, $index) );
        -
        -    $self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New(::TOPIC_FUNCTION(), 'operator ' . $name,
        -                                                                                              $self->CurrentScope(), $self->CurrentUsing(),
        -                                                                                              $prototype,
        -                                                                                              undef, undef, $startLine));
        -
        -    $self->SkipRestOfStatement(\$index, \$lineNumber);
        -
        -
        -    # We succeeded if we got this far.
        -
        -    $$indexRef = $index;
        -    $$lineNumberRef = $lineNumber;
        -
        -    return 1;
        -    };
        -
        -
        -#
        -#   Function: TryToGetVariable
        -#
        -#   Determines if the position is on a variable declaration statement, and if so, generates a topic for each variable, skips the
        -#   statement, and returns true.
        -#
        -#   Supported Syntaxes:
        -#
        -#       - Variables
        -#       - Constants
        -#
        -sub TryToGetVariable #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $index = $$indexRef;
        -    my $lineNumber = $$lineNumberRef;
        -
        -    if ($self->TryToSkipAttributes(\$index, \$lineNumber))
        -        {  $self->TryToSkipWhitespace(\$index, \$lineNumber);  };
        -
        -    my $startIndex = $index;
        -    my $startLine = $lineNumber;
        -
        -    my @modifiers;
        -
        -    while ($tokens->[$index] =~ /^[a-z]/i &&
        -              exists $variableModifiers{lc($tokens->[$index])} )
        -        {
        -        push @modifiers, lc($tokens->[$index]);
        -        $index++;
        -
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        };
        -
        -    my $type;
        -    if (lc($tokens->[$index]) eq 'const')
        -        {
        -        $type = ::TOPIC_CONSTANT();
        -        $index++;
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        }
        -    else
        -        {
        -        $type = ::TOPIC_VARIABLE();
        -        };
        -
        -    if (!$self->TryToGetType(\$index, \$lineNumber))
        -        {  return undef;  };
        -
        -    my $endTypeIndex = $index;
        -
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -    my @names;
        -
        -    for (;;)
        -        {
        -        my $name;
        -
        -        while ($tokens->[$index] =~ /^[a-z\@\_]/i)
        -            {
        -            $name .= $tokens->[$index];
        -            $index++;
        -            };
        -
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        if ($tokens->[$index] eq '=')
        -            {
        -            do
        -                {
        -                $self->GenericSkip(\$index, \$lineNumber);
        -                }
        -            while ($tokens->[$index] ne ',' && $tokens->[$index] ne ';');
        -            };
        -
        -        push @names, $name;
        -
        -        if ($tokens->[$index] eq ';')
        -            {
        -            $index++;
        -            last;
        -            }
        -        elsif ($tokens->[$index] eq ',')
        -            {
        -            $index++;
        -            $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -            }
        -        else
        -            {  return undef;  };
        -        };
        -
        -
        -    # We succeeded if we got this far.
        -
        -    my $prototypePrefix = $self->CreateString($startIndex, $endTypeIndex);
        -
        -    foreach my $name (@names)
        -        {
        -        my $prototype = $self->NormalizePrototype( $prototypePrefix . ' ' . $name );
        -
        -        $self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New($type, $name,
        -                                                                                                  $self->CurrentScope(), $self->CurrentUsing(),
        -                                                                                                  $prototype,
        -                                                                                                  undef, undef, $startLine));
        -        };
        -
        -    $$indexRef = $index;
        -    $$lineNumberRef = $lineNumber;
        -
        -    return 1;
        -    };
        -
        -
        -#
        -#   Function: TryToGetEnum
        -#
        -#   Determines if the position is on an enum declaration statement, and if so, generates a topic for it.
        -#
        -#   Supported Syntaxes:
        -#
        -#       - Enums
        -#       - Enums with declared types
        -#
        -#   Unsupported:
        -#
        -#       - Documenting the members automatically
        -#
        -sub TryToGetEnum #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $index = $$indexRef;
        -    my $lineNumber = $$lineNumberRef;
        -
        -    if ($self->TryToSkipAttributes(\$index, \$lineNumber))
        -        {  $self->TryToSkipWhitespace(\$index, \$lineNumber);  };
        -
        -    my $startIndex = $index;
        -    my $startLine = $lineNumber;
        -
        -    my @modifiers;
        -
        -    while ($tokens->[$index] =~ /^[a-z]/i &&
        -              exists $variableModifiers{lc($tokens->[$index])} )
        -        {
        -        push @modifiers, lc($tokens->[$index]);
        -        $index++;
        -
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        };
        -
        -    if (lc($tokens->[$index]) ne 'enum')
        -        {  return undef;  }
        -
        -    $index++;
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -    my $name;
        -
        -    while ($tokens->[$index] =~ /^[a-z\@\_]/i)
        -        {
        -        $name .= $tokens->[$index];
        -        $index++;
        -        };
        -
        -    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -    if ($tokens->[$index] eq ':')
        -        {
        -        $index++;
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        if (!exists $enumTypes{ lc($tokens->[$index]) })
        -            {  return undef;  }
        -
        -        $index++;
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        }
        -
        -    if ($tokens->[$index] ne '{')
        -        {  return undef;  }
        -
        -    # We succeeded if we got this far.
        -
        -    my $prototype = $self->CreateString($startIndex, $index);
        -    $prototype = $self->NormalizePrototype( $prototype );
        -
        -    $self->SkipRestOfStatement(\$index, \$lineNumber);
        -
        -    $self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New(::TOPIC_ENUMERATION(), $name,
        -                                                                                              $self->CurrentScope(), $self->CurrentUsing(),
        -                                                                                              $prototype,
        -                                                                                              undef, undef, $startLine));
        -
        -    $$indexRef = $index;
        -    $$lineNumberRef = $lineNumber;
        -
        -    return 1;
        -    };
        -
        -
        -#
        -#   Function: TryToGetType
        -#
        -#   Determines if the position is on a type identifier, and if so, skips it and returns it as a string.  This function does _not_ allow
        -#   modifiers.  You must take care of those beforehand.
        -#
        -sub TryToGetType #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $name;
        -    my $index = $$indexRef;
        -    my $lineNumber = $$lineNumberRef;
        -
        -    while ($tokens->[$index] =~ /^[a-z\@\.\_]/i)
        -        {
        -		# Case sensitive since you can declare a class Lock even though lock is a keyword.
        -        if (exists $impossibleTypeWords{ $tokens->[$index] } && $name !~ /\@$/)
        -            {  return undef;  };
        -
        -        $name .= $tokens->[$index];
        -        $index++;
        -        };
        -
        -    if (!defined $name)
        -        {  return undef;  };
        -
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        if ($tokens->[$index] eq '?')
        -                {
        -                $name .= '?';
        -                $index++;
        -
        -                $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -                }
        -
        -    if ($self->TryToSkipTemplateSpec(\$index, \$lineNumber))
        -    	{  $self->TryToSkipWhitespace(\$index, \$lineNumber);  }
        -
        -    while ($tokens->[$index] eq '[')
        -        {
        -        $name .= '[';
        -        $index++;
        -
        -        while ($tokens->[$index] eq ',')
        -            {
        -            $name .= ',';
        -            $index++;
        -            };
        -
        -        if ($tokens->[$index] eq ']')
        -            {
        -            $name .= ']';
        -            $index++;
        -            }
        -        else
        -            {  return undef;  }
        -        };
        -
        -    $$indexRef = $index;
        -    $$lineNumberRef = $lineNumber;
        -
        -    return $name;
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Low Level Parsing Functions
        -
        -
        -#
        -#   Function: GenericSkip
        -#
        -#   Advances the position one place through general code.
        -#
        -#   - If the position is on a string, it will skip it completely.
        -#   - If the position is on an opening symbol, it will skip until the past the closing symbol.
        -#   - If the position is on whitespace (including comments and preprocessing directives), it will skip it completely.
        -#   - Otherwise it skips one token.
        -#
        -#   Parameters:
        -#
        -#       indexRef - A reference to the current index.
        -#       lineNumberRef - A reference to the current line number.
        -#
        -sub GenericSkip #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    # We can ignore the scope stack because we're just skipping everything without parsing, and we need recursion anyway.
        -    if ($tokens->[$$indexRef] eq '{')
        -        {
        -        $$indexRef++;
        -        $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, '}');
        -        }
        -    elsif ($tokens->[$$indexRef] eq '(')
        -        {
        -        $$indexRef++;
        -        $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, ')');
        -        }
        -    elsif ($tokens->[$$indexRef] eq '[')
        -        {
        -        $$indexRef++;
        -        $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, ']');
        -        }
        -
        -    elsif ($self->TryToSkipWhitespace($indexRef, $lineNumberRef) ||
        -            $self->TryToSkipString($indexRef, $lineNumberRef))
        -        {
        -        }
        -
        -    else
        -        {  $$indexRef++;  };
        -    };
        -
        -
        -#
        -#   Function: GenericSkipUntilAfter
        -#
        -#   Advances the position via <GenericSkip()> until a specific token is reached and passed.
        -#
        -sub GenericSkipUntilAfter #(indexRef, lineNumberRef, token)
        -    {
        -    my ($self, $indexRef, $lineNumberRef, $token) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    while ($$indexRef < scalar @$tokens && $tokens->[$$indexRef] ne $token)
        -        {  $self->GenericSkip($indexRef, $lineNumberRef);  };
        -
        -    if ($tokens->[$$indexRef] eq "\n")
        -        {  $$lineNumberRef++;  };
        -    $$indexRef++;
        -    };
        -
        -
        -#
        -#   Function: SkipRestOfStatement
        -#
        -#   Advances the position via <GenericSkip()> until after the end of the current statement, which is defined as a semicolon or
        -#   a brace group.  Of course, either of those appearing inside parenthesis, a nested brace group, etc. don't count.
        -#
        -sub SkipRestOfStatement #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    while ($$indexRef < scalar @$tokens &&
        -             $tokens->[$$indexRef] ne ';' &&
        -             $tokens->[$$indexRef] ne '{')
        -        {
        -        $self->GenericSkip($indexRef, $lineNumberRef);
        -        };
        -
        -    if ($tokens->[$$indexRef] eq ';')
        -        {  $$indexRef++;  }
        -    elsif ($tokens->[$$indexRef] eq '{')
        -        {  $self->GenericSkip($indexRef, $lineNumberRef);  };
        -    };
        -
        -
        -#
        -#   Function: TryToSkipString
        -#   If the current position is on a string delimiter, skip past the string and return true.
        -#
        -#   Parameters:
        -#
        -#       indexRef - A reference to the index of the position to start at.
        -#       lineNumberRef - A reference to the line number of the position.
        -#
        -#   Returns:
        -#
        -#       Whether the position was at a string.
        -#
        -#   Syntax Support:
        -#
        -#       - Supports quotes, apostrophes, and at-quotes.
        -#
        -sub TryToSkipString #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    # The three string delimiters.  All three are Perl variables when preceded by a dollar sign.
        -    if ($self->SUPER::TryToSkipString($indexRef, $lineNumberRef, '\'') ||
        -        $self->SUPER::TryToSkipString($indexRef, $lineNumberRef, '"') )
        -        {
        -        return 1;
        -        }
        -    elsif ($tokens->[$$indexRef] eq '@' && $tokens->[$$indexRef+1] eq '"')
        -        {
        -        $$indexRef += 2;
        -
        -        # We need to do at-strings manually because backslash characters are accepted as regular characters, and two consecutive
        -        # quotes are accepted as well.
        -
        -        while ($$indexRef < scalar @$tokens && !($tokens->[$$indexRef] eq '"' && $tokens->[$$indexRef+1] ne '"') )
        -            {
        -            if ($tokens->[$$indexRef] eq '"')
        -                {
        -                # This is safe because the while condition will only let through quote pairs.
        -                $$indexRef += 2;
        -                }
        -            elsif ($tokens->[$$indexRef] eq "\n")
        -                {
        -                $$indexRef++;
        -                $$lineNumberRef++;
        -                }
        -            else
        -                {
        -                $$indexRef++;
        -                };
        -            };
        -
        -        # Skip the closing quote.
        -        if ($$indexRef < scalar @$tokens)
        -            {  $$indexRef++;  };
        -
        -        return 1;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: TryToSkipAttributes
        -#   If the current position is on an attribute section, skip it and return true.  Skips multiple attribute sections if they appear
        -#   consecutively.
        -#
        -sub TryToSkipAttributes #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $success;
        -
        -    while ($tokens->[$$indexRef] eq '[')
        -        {
        -        $success = 1;
        -        $$indexRef++;
        -        $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, ']');
        -        $self->TryToSkipWhitespace($indexRef, $lineNumberRef);
        -        };
        -
        -    return $success;
        -    };
        -
        -
        -#
        -#	Function: TryToSkipTemplateSpec
        -#	If the current position is on a template spec (the part in angle brackets) skip it and return true.  Can handle nested
        -#	templates.
        -#
        -sub TryToSkipTemplateSpec #(indexRef, lineNumberRef)
        -	{
        -	my ($self, $indexRef, $lineNumberRef) = @_;
        -	my $tokens = $self->Tokens();
        -
        -    if ($tokens->[$$indexRef] eq '<')
        -        {
        -        my $nestingLevel = 1;
        -        $$indexRef++;
        -        $self->TryToSkipWhitespace($indexRef, $lineNumberRef);
        -
        -        while ($$indexRef < scalar @$tokens && $nestingLevel > 0)
        -        	{
        -        	if ($tokens->[$$indexRef] eq '<')
        -        		{  $nestingLevel++;  }
        -        	elsif ($tokens->[$$indexRef] eq '>')
        -        		{  $nestingLevel--;  }
        -
        -            $$indexRef++;
        -        	$self->TryToSkipWhitespace($indexRef, $lineNumberRef);
        -			}
        -
        -		return 1;
        -        }
        -    else
        -    	{  return undef;  }
        -	}
        -
        -
        -#
        -#	Function: TryToSkipWhereClauses
        -#	If the current position is on a "where" clause, skips it and returns true.  Can handle multiple wheres in a row.
        -#
        -sub TryToSkipWhereClauses #(indexRef, lineNumberRef)
        -	{
        -	my ($self, $indexRef, $lineNumberRef) = @_;
        -	my $tokens = $self->Tokens();
        -
        -    if ($tokens->[$$indexRef] ne 'where')
        -    	{  return undef;  }
        -
        -	my $index = $$indexRef;
        -	my $lineNumber = $$lineNumberRef;
        -
        -    do
        -        {
        -        $index++;  # Skip the where
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        $index++;  # Skip the variable name
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        if ($tokens->[$index] ne ':')
        -        	{  return undef;  }
        -
        -        $index++;  # Skip the colon
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        for (;;)
        -        	{
        -        	if ($index >= scalar @$tokens)
        -        		{  return undef;  }
        -        	elsif ($tokens->[$index] eq 'new')
        -        		{
        -        		$index++;
        -        		$self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        		if ($tokens->[$index] ne '(')
        -        			{  return undef;  }
        -
        -                $index++;
        -        		$self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        		if ($tokens->[$index] ne ')')
        -        			{  return undef;  }
        -
        -        		$index++;
        -        		$self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        		}
        -        	else
        -        		{
        -        		while ($index < scalar @$tokens && $tokens->[$index] =~ /^[a-z0-9_\.\@]+$/i)
        -        			{  $index++;  }
        -
        -        		$self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        		if ($self->TryToSkipTemplateSpec(\$index, \$lineNumber))
        -        			{  $self->TryToSkipWhitespace(\$index, \$lineNumber);  }
        -        		}
        -
        -        	if ($tokens->[$index] eq ',')
        -        		{
        -        		$index++;
        -        		$self->TryToSkipWhitespace(\$index, \$lineNumber);
        -        		}
        -        	else
        -        		{  last;  }
        -        	}
        -        }
        -    while ($tokens->[$index] eq 'where');
        -
        -    $$indexRef = $index;
        -    $$lineNumberRef = $lineNumber;
        -
        -    return 1;
        -	}
        -
        -
        -#
        -#   Function: TryToSkipWhitespace
        -#   If the current position is on a whitespace token, a line break token, a comment, or a preprocessing directive, it skips them
        -#   and returns true.  If there are a number of these in a row, it skips them all.
        -#
        -sub TryToSkipWhitespace #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $result;
        -
        -    while ($$indexRef < scalar @$tokens)
        -        {
        -        if ($tokens->[$$indexRef] =~ /^[ \t]/)
        -            {
        -            $$indexRef++;
        -            $result = 1;
        -            }
        -        elsif ($tokens->[$$indexRef] eq "\n")
        -            {
        -            $$indexRef++;
        -            $$lineNumberRef++;
        -            $result = 1;
        -            }
        -        elsif ($self->TryToSkipComment($indexRef, $lineNumberRef) ||
        -                $self->TryToSkipPreprocessingDirective($indexRef, $lineNumberRef))
        -            {
        -            $result = 1;
        -            }
        -        else
        -            {  last;  };
        -        };
        -
        -    return $result;
        -    };
        -
        -
        -#
        -#   Function: TryToSkipComment
        -#   If the current position is on a comment, skip past it and return true.
        -#
        -sub TryToSkipComment #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -
        -    return ( $self->TryToSkipLineComment($indexRef, $lineNumberRef) ||
        -                $self->TryToSkipMultilineComment($indexRef, $lineNumberRef) );
        -    };
        -
        -
        -#
        -#   Function: TryToSkipLineComment
        -#   If the current position is on a line comment symbol, skip past it and return true.
        -#
        -sub TryToSkipLineComment #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($tokens->[$$indexRef] eq '/' && $tokens->[$$indexRef+1] eq '/')
        -        {
        -        $self->SkipRestOfLine($indexRef, $lineNumberRef);
        -        return 1;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: TryToSkipMultilineComment
        -#   If the current position is on an opening comment symbol, skip past it and return true.
        -#
        -sub TryToSkipMultilineComment #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($tokens->[$$indexRef] eq '/' && $tokens->[$$indexRef+1] eq '*')
        -        {
        -        $self->SkipUntilAfter($indexRef, $lineNumberRef, '*', '/');
        -        return 1;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: TryToSkipPreprocessingDirective
        -#   If the current position is on a preprocessing directive, skip past it and return true.
        -#
        -sub TryToSkipPreprocessingDirective #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($tokens->[$$indexRef] eq '#' && $self->IsFirstLineToken($$indexRef))
        -        {
        -        $self->SkipRestOfLine($indexRef, $lineNumberRef);
        -        return 1;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages/PLSQL.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages/PLSQL.pm
        deleted file mode 100644
        index c72db78cb..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages/PLSQL.pm
        +++ /dev/null
        @@ -1,320 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Languages::PLSQL
        -#
        -###############################################################################
        -#
        -#   A subclass to handle the language variations of PL/SQL.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Languages::PLSQL;
        -
        -use base 'NaturalDocs::Languages::Simple';
        -
        -
        -#
        -#   Function: OnPrototypeEnd
        -#
        -#   Microsoft's SQL specifies parameters as shown below.
        -#
        -#   > CREATE PROCEDURE Test @as int, @foo int AS ...
        -#
        -#   Having a parameter @is or @as is perfectly valid even though those words are also used to end the prototype.  We need to
        -#   ignore text-based enders preceded by an at sign.  Also note that it does not have parenthesis for parameter lists.  We need to
        -#   skip all commas if the prototype doesn't have parenthesis but does have @ characters.
        -#
        -#	Identifiers such as function names may contain the characters $, #, and _, so if "as" or "is" appears directly after one of them
        -#	we need to ignore the ender there as well.
        -#
        -#	> FUNCTION Something_is_something ...
        -#
        -#   Parameters:
        -#
        -#       type - The <TopicType> of the prototype.
        -#       prototypeRef - A reference to the prototype so far, minus the ender in dispute.
        -#       ender - The ender symbol.
        -#
        -#   Returns:
        -#
        -#       ENDER_ACCEPT - The ender is accepted and the prototype is finished.
        -#       ENDER_IGNORE - The ender is rejected and parsing should continue.  Note that the prototype will be rejected as a whole
        -#                                  if all enders are ignored before reaching the end of the code.
        -#       ENDER_ACCEPT_AND_CONTINUE - The ender is accepted so the prototype may stand as is.  However, the prototype might
        -#                                                          also continue on so continue parsing.  If there is no accepted ender between here and
        -#                                                          the end of the code this version will be accepted instead.
        -#       ENDER_REVERT_TO_ACCEPTED - The expedition from ENDER_ACCEPT_AND_CONTINUE failed.  Use the last accepted
        -#                                                        version and end parsing.
        -#
        -sub OnPrototypeEnd #(type, prototypeRef, ender)
        -    {
        -    my ($self, $type, $prototypeRef, $ender) = @_;
        -
        -    # _ should be handled already.
        -    if ($ender =~ /^[a-z]+$/i && substr($$prototypeRef, -1) =~ /^[\@\$\#]$/)
        -        {  return ::ENDER_IGNORE();  }
        -
        -    elsif ($type eq ::TOPIC_FUNCTION() && $ender eq ',')
        -        {
        -        if ($$prototypeRef =~ /^[^\(]*\@/)
        -            {  return ::ENDER_IGNORE();  }
        -        else
        -            {  return ::ENDER_ACCEPT();  };
        -        }
        -
        -    else
        -        {  return ::ENDER_ACCEPT();  };
        -    };
        -
        -
        -#
        -#   Function: ParsePrototype
        -#
        -#   Overridden to handle Microsoft's parenthesisless version.  Otherwise just throws to the parent.
        -#
        -#   Parameters:
        -#
        -#       type - The <TopicType>.
        -#       prototype - The text prototype.
        -#
        -#   Returns:
        -#
        -#       A <NaturalDocs::Languages::Prototype> object.
        -#
        -sub ParsePrototype #(type, prototype)
        -    {
        -    my ($self, $type, $prototype) = @_;
        -
        -    my $noParenthesisParameters = ($type eq ::TOPIC_FUNCTION() && $prototype =~ /^[^\(]*\@/);
        -
        -    if ($prototype !~ /\(.*[^ ].*\)/ && !$noParenthesisParameters)
        -        {  return $self->SUPER::ParsePrototype($type, $prototype);  };
        -
        -
        -
        -    my ($beforeParameters, $afterParameters, $isAfterParameters);
        -
        -    if ($noParenthesisParameters)
        -        {
        -        ($beforeParameters, $prototype) = split(/\@/, $prototype, 2);
        -        $prototype = '@' . $prototype;
        -        };
        -
        -    my @tokens = $prototype =~ /([^\(\)\[\]\{\}\<\>\'\"\,]+|.)/g;
        -
        -    my $parameter;
        -    my @parameterLines;
        -
        -    my @symbolStack;
        -
        -    foreach my $token (@tokens)
        -        {
        -        if ($isAfterParameters)
        -            {  $afterParameters .= $token;  }
        -
        -        elsif ($symbolStack[-1] eq '\'' || $symbolStack[-1] eq '"')
        -            {
        -            if ($noParenthesisParameters || $symbolStack[0] eq '(')
        -                {  $parameter .= $token;  }
        -            else
        -                {  $beforeParameters .= $token;  };
        -
        -            if ($token eq $symbolStack[-1])
        -                {  pop @symbolStack;  };
        -            }
        -
        -        elsif ($token =~ /^[\(\[\{\<\'\"]$/)
        -            {
        -            if ($noParenthesisParameters || $symbolStack[0] eq '(')
        -                {  $parameter .= $token;  }
        -            else
        -                {  $beforeParameters .= $token;  };
        -
        -            push @symbolStack, $token;
        -            }
        -
        -        elsif ( ($token eq ')' && $symbolStack[-1] eq '(') ||
        -                 ($token eq ']' && $symbolStack[-1] eq '[') ||
        -                 ($token eq '}' && $symbolStack[-1] eq '{') ||
        -                 ($token eq '>' && $symbolStack[-1] eq '<') )
        -            {
        -            if (!$noParenthesisParameters && $token eq ')' && scalar @symbolStack == 1 && $symbolStack[0] eq '(')
        -                {
        -                $afterParameters .= $token;
        -                $isAfterParameters = 1;
        -                }
        -            else
        -                {  $parameter .= $token;  };
        -
        -            pop @symbolStack;
        -            }
        -
        -        elsif ($token eq ',')
        -            {
        -            if (!scalar @symbolStack)
        -                {
        -                if ($noParenthesisParameters)
        -                    {
        -                    push @parameterLines, $parameter . $token;
        -                    $parameter = undef;
        -                    }
        -                else
        -                    {
        -                    $beforeParameters .= $token;
        -                    };
        -                }
        -            else
        -                {
        -                if (scalar @symbolStack == 1 && $symbolStack[0] eq '(' && !$noParenthesisParameters)
        -                    {
        -                    push @parameterLines, $parameter . $token;
        -                    $parameter = undef;
        -                    }
        -                else
        -                    {
        -                    $parameter .= $token;
        -                    };
        -                };
        -            }
        -
        -        else
        -            {
        -            if ($noParenthesisParameters || $symbolStack[0] eq '(')
        -                {  $parameter .= $token;  }
        -            else
        -                {  $beforeParameters .= $token;  };
        -            };
        -        };
        -
        -    push @parameterLines, $parameter;
        -
        -    foreach my $item (\$beforeParameters, \$afterParameters)
        -        {
        -        $$item =~ s/^ //;
        -        $$item =~ s/ $//;
        -        }
        -
        -    my $prototypeObject = NaturalDocs::Languages::Prototype->New($beforeParameters, $afterParameters);
        -
        -
        -    # Parse the actual parameters.
        -
        -    foreach my $parameterLine (@parameterLines)
        -        {
        -        $prototypeObject->AddParameter( $self->ParseParameterLine($parameterLine) );
        -        };
        -
        -    return $prototypeObject;
        -    };
        -
        -
        -#
        -#   Function: ParseParameterLine
        -#
        -#   Parses a prototype parameter line and returns it as a <NaturalDocs::Languages::Prototype::Parameter> object.
        -#
        -sub ParseParameterLine #(line)
        -    {
        -    my ($self, $line) = @_;
        -
        -    $line =~ s/^ //;
        -    $line =~ s/ $//;
        -
        -    my @tokens = $line =~ /([^\(\)\[\]\{\}\<\>\'\"\:\=\ ]+|\:\=|.)/g;
        -
        -    my ($name, $type, $defaultValue, $defaultValuePrefix, $inType, $inDefaultValue);
        -
        -
        -    my @symbolStack;
        -
        -    foreach my $token (@tokens)
        -        {
        -        if ($inDefaultValue)
        -            {  $defaultValue .= $token;  }
        -
        -        elsif ($symbolStack[-1] eq '\'' || $symbolStack[-1] eq '"')
        -            {
        -            if ($inType)
        -                {  $type .= $token;  }
        -            else
        -                {  $name .= $token;  };
        -
        -            if ($token eq $symbolStack[-1])
        -                {  pop @symbolStack;  };
        -            }
        -
        -        elsif ($token =~ /^[\(\[\{\<\'\"]$/)
        -            {
        -            if ($inType)
        -                {  $type .= $token;  }
        -            else
        -                {  $name .= $token;  };
        -
        -            push @symbolStack, $token;
        -            }
        -
        -        elsif ( ($token eq ')' && $symbolStack[-1] eq '(') ||
        -                 ($token eq ']' && $symbolStack[-1] eq '[') ||
        -                 ($token eq '}' && $symbolStack[-1] eq '{') ||
        -                 ($token eq '>' && $symbolStack[-1] eq '<') )
        -            {
        -            if ($inType)
        -                {  $type .= $token;  }
        -            else
        -                {  $name .= $token;  };
        -
        -            pop @symbolStack;
        -            }
        -
        -        elsif ($token eq ' ')
        -            {
        -            if ($inType)
        -                {  $type .= $token;  }
        -            elsif (!scalar @symbolStack)
        -                {  $inType = 1;  }
        -            else
        -                {  $name .= $token;  };
        -            }
        -
        -        elsif ($token eq ':=' || $token eq '=')
        -            {
        -            if (!scalar @symbolStack)
        -                {
        -                $defaultValuePrefix = $token;
        -                $inDefaultValue = 1;
        -                }
        -            elsif ($inType)
        -                {  $type .= $token;  }
        -            else
        -                {  $name .= $token;  };
        -            }
        -
        -        else
        -            {
        -            if ($inType)
        -                {  $type .= $token;  }
        -            else
        -                {  $name .= $token;  };
        -            };
        -        };
        -
        -    foreach my $part (\$type, \$defaultValue)
        -        {
        -        $$part =~ s/ $//;
        -        };
        -
        -    return NaturalDocs::Languages::Prototype::Parameter->New($type, undef, $name, undef, $defaultValue, $defaultValuePrefix);
        -    };
        -
        -
        -sub TypeBeforeParameter
        -    {  return 0;  };
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Pascal.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages/Pascal.pm
        deleted file mode 100644
        index 69cf56784..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Pascal.pm
        +++ /dev/null
        @@ -1,144 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Languages::Pascal
        -#
        -###############################################################################
        -#
        -#   A subclass to handle the language variations of Pascal and Delphi.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Languages::Pascal;
        -
        -use base 'NaturalDocs::Languages::Simple';
        -
        -
        -#
        -#   hash: prototypeDirectives
        -#
        -#   An existence hash of all the directives that can appear after a function prototype and will be included.  The keys are the all
        -#   lowercase keywords.
        -#
        -my %prototypeDirectives = ( 'overload' => 1,
        -                                           'override' => 1,
        -                                           'virtual' => 1,
        -                                           'abstract' => 1,
        -                                           'reintroduce' => 1,
        -                                           'export' => 1,
        -                                           'public' => 1,
        -                                           'interrupt' => 1,
        -                                           'register' => 1,
        -                                           'pascal' => 1,
        -                                           'cdecl' => 1,
        -                                           'stdcall' => 1,
        -                                           'popstack' => 1,
        -                                           'saveregisters' => 1,
        -                                           'inline' => 1,
        -                                           'safecall' => 1 );
        -
        -#
        -#   hash: longPrototypeDirectives
        -#
        -#   An existence hash of all the directives with parameters that can appear after a function prototype and will be included.  The
        -#   keys are the all lowercase keywords.
        -#
        -my %longPrototypeDirectives = ( 'alias' => 1,
        -                                                 'external' => 1 );
        -
        -#
        -#   bool: checkingForDirectives
        -#
        -#   Set after the first function semicolon, which means we're in directives mode.
        -#
        -my $checkingForDirectives;
        -
        -
        -#
        -#   Function: OnCode
        -#
        -#   Just overridden to reset <checkingForDirectives>.
        -#
        -sub OnCode #(...)
        -    {
        -    my ($self, @parameters) = @_;
        -
        -    $checkingForDirectives = 0;
        -
        -    return $self->SUPER::OnCode(@parameters);
        -    };
        -
        -
        -#
        -#   Function: OnPrototypeEnd
        -#
        -#   Pascal's syntax has directives after the prototype that should be included.
        -#
        -#   > function MyFunction ( param1: type ); virtual; abstract;
        -#
        -#   Parameters:
        -#
        -#       type - The <TopicType> of the prototype.
        -#       prototypeRef - A reference to the prototype so far, minus the ender in dispute.
        -#       ender - The ender symbol.
        -#
        -#   Returns:
        -#
        -#       ENDER_ACCEPT - The ender is accepted and the prototype is finished.
        -#       ENDER_IGNORE - The ender is rejected and parsing should continue.  Note that the prototype will be rejected as a whole
        -#                                  if all enders are ignored before reaching the end of the code.
        -#       ENDER_ACCEPT_AND_CONTINUE - The ender is accepted so the prototype may stand as is.  However, the prototype might
        -#                                                          also continue on so continue parsing.  If there is no accepted ender between here and
        -#                                                          the end of the code this version will be accepted instead.
        -#       ENDER_REVERT_TO_ACCEPTED - The expedition from ENDER_ACCEPT_AND_CONTINUE failed.  Use the last accepted
        -#                                                        version and end parsing.
        -#
        -sub OnPrototypeEnd #(type, prototypeRef, ender)
        -    {
        -    my ($self, $type, $prototypeRef, $ender) = @_;
        -
        -    if ($type eq ::TOPIC_FUNCTION() && $ender eq ';')
        -        {
        -        if (!$checkingForDirectives)
        -            {
        -            $checkingForDirectives = 1;
        -            return ::ENDER_ACCEPT_AND_CONTINUE();
        -            }
        -        elsif ($$prototypeRef =~ /;[ \t]*([a-z]+)([^;]*)$/i)
        -            {
        -            my ($lastDirective, $extra) = (lc($1), $2);
        -
        -            if (exists $prototypeDirectives{$lastDirective} && $extra =~ /^[ \t]*$/)
        -                {  return ::ENDER_ACCEPT_AND_CONTINUE();  }
        -            elsif (exists $longPrototypeDirectives{$lastDirective})
        -                {  return ::ENDER_ACCEPT_AND_CONTINUE();  }
        -            else
        -                {  return ::ENDER_REVERT_TO_ACCEPTED();  };
        -            }
        -        else
        -            {  return ::ENDER_REVERT_TO_ACCEPTED();  };
        -        }
        -    else
        -        {  return ::ENDER_ACCEPT();  };
        -    };
        -
        -
        -sub ParseParameterLine #(...)
        -    {
        -    my ($self, @params) = @_;
        -    return $self->SUPER::ParsePascalParameterLine(@params);
        -    };
        -
        -sub TypeBeforeParameter
        -    {
        -    return 0;
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Perl.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages/Perl.pm
        deleted file mode 100644
        index 5d971b8d5..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Perl.pm
        +++ /dev/null
        @@ -1,1371 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Languages::Perl
        -#
        -###############################################################################
        -#
        -#   A subclass to handle the language variations of Perl.
        -#
        -#
        -#   Topic: Language Support
        -#
        -#       Supported:
        -#
        -#       - Packages
        -#       - Inheritance via "use base" and "@ISA =".
        -#       - Functions
        -#       - Variables
        -#
        -#       Not supported yet:
        -#
        -#       - Constants
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Languages::Perl;
        -
        -use base 'NaturalDocs::Languages::Advanced';
        -
        -
        -#
        -#   array: hereDocTerminators
        -#   An array of active Here Doc terminators, or an empty array if not active.  Each entry is an arrayref of tokens.  The entries
        -#   must appear in the order they must appear in the source.
        -#
        -my @hereDocTerminators;
        -
        -
        -
        -###############################################################################
        -# Group: Interface Functions
        -
        -
        -#
        -#   Function: PackageSeparator
        -#   Returns the package separator symbol.
        -#
        -sub PackageSeparator
        -    {  return '::';  };
        -
        -#
        -#   Function: EnumValues
        -#   Returns the <EnumValuesType> that describes how the language handles enums.
        -#
        -sub EnumValues
        -    {  return ::ENUM_GLOBAL();  };
        -
        -
        -#
        -#   Function: ParseFile
        -#
        -#   Parses the passed source file, sending comments acceptable for documentation to <NaturalDocs::Parser->OnComment()>.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The name of the source file to parse.
        -#       topicList - A reference to the list of <NaturalDocs::Parser::ParsedTopics> being built by the file.
        -#
        -#   Returns:
        -#
        -#       The array ( autoTopics, scopeRecord ).
        -#
        -#       autoTopics - An arrayref of automatically generated topics from the file, or undef if none.
        -#       scopeRecord - An arrayref of <NaturalDocs::Languages::Advanced::ScopeChanges>, or undef if none.
        -#
        -sub ParseFile #(sourceFile, topicsList)
        -    {
        -    my ($self, $sourceFile, $topicsList) = @_;
        -
        -    @hereDocTerminators = ( );
        -
        -    # The regular block comment symbols are undef because they're all potentially JavaDoc comments.  PreprocessFile() will
        -    # handle translating things like =begin naturaldocs and =begin javadoc to =begin nd.
        -    $self->ParseForCommentsAndTokens($sourceFile, [ '#' ], undef, [ '##' ], [ '=begin nd', '=end nd' ]);
        -
        -    my $tokens = $self->Tokens();
        -    my $index = 0;
        -    my $lineNumber = 1;
        -
        -    while ($index < scalar @$tokens)
        -        {
        -        if ($self->TryToSkipWhitespace(\$index, \$lineNumber) ||
        -            $self->TryToGetPackage(\$index, \$lineNumber) ||
        -            $self->TryToGetBase(\$index, \$lineNumber) ||
        -            $self->TryToGetFunction(\$index, \$lineNumber) ||
        -            $self->TryToGetVariable(\$index, \$lineNumber) )
        -            {
        -            # The functions above will handle everything.
        -            }
        -
        -        elsif ($tokens->[$index] eq '{')
        -            {
        -            $self->StartScope('}', $lineNumber, undef);
        -            $index++;
        -            }
        -
        -        elsif ($tokens->[$index] eq '}')
        -            {
        -            if ($self->ClosingScopeSymbol() eq '}')
        -                {  $self->EndScope($lineNumber);  };
        -
        -            $index++;
        -            }
        -
        -        elsif (lc($tokens->[$index]) eq 'eval')
        -            {
        -            # We want to skip the token in this case instead of letting it fall to SkipRestOfStatement.  This allows evals with braces
        -            # to be treated like normal floating braces.
        -            $index++;
        -            }
        -
        -        else
        -            {
        -            $self->SkipRestOfStatement(\$index, \$lineNumber);
        -            };
        -        };
        -
        -
        -    # Don't need to keep these around.
        -    $self->ClearTokens();
        -
        -    return ( $self->AutoTopics(), $self->ScopeRecord() );
        -    };
        -
        -
        -#
        -#   Function: PreprocessFile
        -#
        -#   Overridden to support "=begin nd" and similar.
        -#
        -#   - "=begin [nd|naturaldocs|natural docs|jd|javadoc|java doc]" all translate to "=begin nd".
        -#   - "=[nd|naturaldocs|natural docs]" also translate to "=begin nd".
        -#   - "=end [nd|naturaldocs|natural docs|jd|javadoc]" all translate to "=end nd".
        -#   - "=cut" from a ND block translates into "=end nd", but the next line will be altered to begin with "(NDPODBREAK)".  This is
        -#     so if there is POD leading into ND which ends with a cut, the parser can still end the original POD because the end ND line
        -#     would have been removed.  Remember, <NaturalDocs::Languages::Advanced->ParseForCommentsAndTokens()> removes
        -#     Natural Docs-worthy comments to save parsing time.
        -#   - "=pod begin nd" and "=pod end nd" are supported for compatibility with ND 1.32 and earlier, even though the syntax is a
        -#     mistake.
        -#   - It also supports the wrong plural forms, so naturaldoc/natural doc/javadocs/java docs will work.
        -#
        -sub PreprocessFile #(lines)
        -    {
        -    my ($self, $lines) = @_;
        -
        -    my $inNDPOD = 0;
        -    my $mustBreakPOD = 0;
        -
        -    for (my $i = 0; $i < scalar @$lines; $i++)
        -        {
        -        if ($lines->[$i] =~ /^\=(?:(?:pod[ \t]+)?begin[ \t]+)?(?:nd|natural[ \t]*docs?|jd|java[ \t]*docs?)[ \t]*$/i)
        -            {
        -            $lines->[$i] = '=begin nd';
        -            $inNDPOD = 1;
        -            $mustBreakPOD = 0;
        -            }
        -        elsif ($lines->[$i] =~ /^\=(?:pod[ \t]+)end[ \t]+(?:nd|natural[ \t]*docs?|jd|javadocs?)[ \t]*$/i)
        -            {
        -            $lines->[$i] = '=end nd';
        -            $inNDPOD = 0;
        -            $mustBreakPOD = 0;
        -            }
        -        elsif ($lines->[$i] =~ /^\=cut[ \t]*$/i)
        -            {
        -            if ($inNDPOD)
        -                {
        -                $lines->[$i] = '=end nd';
        -                $inNDPOD = 0;
        -                $mustBreakPOD = 1;
        -                };
        -            }
        -        elsif ($mustBreakPOD)
        -            {
        -            $lines->[$i] = '(NDPODBREAK)' . $lines->[$i];
        -            $mustBreakPOD = 0;
        -            };
        -        };
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Statement Parsing Functions
        -# All functions here assume that the current position is at the beginning of a statement.
        -#
        -# Note for developers: I am well aware that the code in these functions do not check if we're past the end of the tokens as
        -# often as it should.  We're making use of the fact that Perl will always return undef in these cases to keep the code simpler.
        -
        -
        -#
        -#   Function: TryToGetPackage
        -#
        -#   Determines whether the position is at a package declaration statement, and if so, generates a topic for it, skips it, and
        -#   returns true.
        -#
        -sub TryToGetPackage #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if (lc($tokens->[$$indexRef]) eq 'package')
        -        {
        -        my $index = $$indexRef + 1;
        -        my $lineNumber = $$lineNumberRef;
        -
        -        if (!$self->TryToSkipWhitespace(\$index, \$lineNumber))
        -            {  return undef;  };
        -
        -        my $name;
        -
        -        while ($tokens->[$index] =~ /^[a-z_\:]/i)
        -            {
        -            $name .= $tokens->[$index];
        -            $index++;
        -            };
        -
        -        if (!defined $name)
        -            {  return undef;  };
        -
        -        my $autoTopic = NaturalDocs::Parser::ParsedTopic->New(::TOPIC_CLASS(), $name,
        -                                                                                             undef, undef,
        -                                                                                             undef,
        -                                                                                             undef, undef, $$lineNumberRef);
        -        $self->AddAutoTopic($autoTopic);
        -
        -        NaturalDocs::Parser->OnClass($autoTopic->Symbol());
        -
        -        $self->SetPackage($autoTopic->Symbol(), $$lineNumberRef);
        -
        -        $$indexRef = $index;
        -        $$lineNumberRef = $lineNumber;
        -        $self->SkipRestOfStatement($indexRef, $lineNumberRef);
        -
        -        return 1;
        -        };
        -
        -    return undef;
        -    };
        -
        -
        -#
        -#   Function: TryToGetBase
        -#
        -#   Determines whether the position is at a package base declaration statement, and if so, calls
        -#   <NaturalDocs::Parser->OnClassParent()>.
        -#
        -#   Supported Syntaxes:
        -#
        -#   > use base [list of strings]
        -#   > @ISA = [list of strings]
        -#   > @[package]::ISA = [list of strings]
        -#   > our @ISA = [list of strings]
        -#
        -sub TryToGetBase #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my ($index, $lineNumber, $class, $parents);
        -
        -    if (lc($tokens->[$$indexRef]) eq 'use')
        -        {
        -        $index = $$indexRef + 1;
        -        $lineNumber = $$lineNumberRef;
        -
        -        if (!$self->TryToSkipWhitespace(\$index, \$lineNumber) ||
        -           lc($tokens->[$index]) ne 'base')
        -            {  return undef;  }
        -
        -        $index++;
        -        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -        $parents = $self->TryToGetListOfStrings(\$index, \$lineNumber);
        -        }
        -
        -    else
        -        {
        -        $index = $$indexRef;
        -        $lineNumber = $$lineNumberRef;
        -
        -        if (lc($tokens->[$index]) eq 'our')
        -            {
        -            $index++;
        -            $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -            };
        -
        -        if ($tokens->[$index] eq '@')
        -            {
        -            $index++;
        -
        -            while ($index < scalar @$tokens)
        -                {
        -                if ($tokens->[$index] eq 'ISA')
        -                    {
        -                    $index++;
        -                    $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -                    if ($tokens->[$index] eq '=')
        -                        {
        -                        $index++;
        -                        $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -                        $parents = $self->TryToGetListOfStrings(\$index, \$lineNumber);
        -                        }
        -                    else
        -                        {  last;  };
        -                    }
        -
        -                # If token isn't ISA...
        -                elsif ($tokens->[$index] =~ /^[a-z0-9_:]/i)
        -                    {
        -                    $class .= $tokens->[$index];
        -                    $index++;
        -                    }
        -                else
        -                    {  last;  };
        -                };
        -            };
        -        };
        -
        -    if (defined $parents)
        -        {
        -        if (defined $class)
        -            {
        -            $class =~ s/::$//;
        -            my @classIdentifiers = split(/::/, $class);
        -            $class = NaturalDocs::SymbolString->Join(@classIdentifiers);
        -            }
        -        else
        -            {  $class = $self->CurrentScope();  };
        -
        -        foreach my $parent (@$parents)
        -            {
        -            my @parentIdentifiers = split(/::/, $parent);
        -            my $parentSymbol = NaturalDocs::SymbolString->Join(@parentIdentifiers);
        -
        -            NaturalDocs::Parser->OnClassParent($class, $parentSymbol, undef, undef, ::RESOLVE_ABSOLUTE());
        -            };
        -
        -        $$indexRef = $index;
        -        $$lineNumberRef = $lineNumber;
        -        $self->SkipRestOfStatement($indexRef, $lineNumberRef);
        -
        -        return 1;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: TryToGetFunction
        -#
        -#   Determines whether the position is at a function declaration statement, and if so, generates a topic for it, skips it, and
        -#   returns true.
        -#
        -sub TryToGetFunction #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ( lc($tokens->[$$indexRef]) eq 'sub')
        -        {
        -        my $prototypeStart = $$indexRef;
        -        my $prototypeStartLine = $$lineNumberRef;
        -        my $prototypeEnd = $$indexRef + 1;
        -        my $prototypeEndLine = $$lineNumberRef;
        -
        -        if ( !$self->TryToSkipWhitespace(\$prototypeEnd, \$prototypeEndLine) ||
        -             $tokens->[$prototypeEnd] !~ /^[a-z_]/i )
        -            {  return undef;  };
        -
        -        my $name = $tokens->[$prototypeEnd];
        -        $prototypeEnd++;
        -
        -        # We parsed 'sub [name]'.  Now keep going until we find a semicolon or a brace.
        -
        -        for (;;)
        -            {
        -            if ($prototypeEnd >= scalar @$tokens)
        -                {  return undef;  }
        -
        -            # End if we find a semicolon, since it means we found a predeclaration rather than an actual function.
        -            elsif ($tokens->[$prototypeEnd] eq ';')
        -                {  return undef;  }
        -
        -            elsif ($tokens->[$prototypeEnd] eq '{')
        -                {
        -                # Found it!
        -
        -                my $prototype = $self->NormalizePrototype( $self->CreateString($prototypeStart, $prototypeEnd) );
        -
        -                $self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New(::TOPIC_FUNCTION(), $name,
        -                                                                                                          $self->CurrentScope(), undef,
        -                                                                                                          $prototype,
        -                                                                                                          undef, undef, $prototypeStartLine));
        -
        -                $$indexRef = $prototypeEnd;
        -                $$lineNumberRef = $prototypeEndLine;
        -
        -                $self->SkipRestOfStatement($indexRef, $lineNumberRef);
        -
        -                return 1;
        -                }
        -
        -            else
        -                {  $self->GenericSkip(\$prototypeEnd, \$prototypeEndLine, 0, 1);  };
        -            };
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: TryToGetVariable
        -#
        -#   Determines if the position is at a variable declaration statement, and if so, generates a topic for it, skips it, and returns
        -#   true.
        -#
        -#   Supported Syntaxes:
        -#
        -#   - Supports variables declared with "my", "our", and "local".
        -#   - Supports multiple declarations in one statement, such as "my ($x, $y);".
        -#   - Supports types and attributes.
        -#
        -sub TryToGetVariable #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $firstToken = lc( $tokens->[$$indexRef] );
        -
        -    if ($firstToken eq 'my' || $firstToken eq 'our' || $firstToken eq 'local')
        -        {
        -        my $prototypeStart = $$indexRef;
        -        my $prototypeStartLine = $$lineNumberRef;
        -        my $prototypeEnd = $$indexRef + 1;
        -        my $prototypeEndLine = $$lineNumberRef;
        -
        -        $self->TryToSkipWhitespace(\$prototypeEnd, \$prototypeEndLine);
        -
        -
        -        # Get the type if present.
        -
        -        my $type;
        -
        -        if ($tokens->[$prototypeEnd] =~ /^[a-z\:]/i)
        -            {
        -            do
        -                {
        -                $type .= $tokens->[$prototypeEnd];
        -                $prototypeEnd++;
        -                }
        -            while ($tokens->[$prototypeEnd] =~ /^[a-z\:]/i);
        -
        -            if (!$self->TryToSkipWhitespace(\$prototypeEnd, \$prototypeEndLine))
        -                {  return undef;  };
        -            };
        -
        -
        -        # Get the name, or possibly names.
        -
        -        if ($tokens->[$prototypeEnd] eq '(')
        -            {
        -            # If there's multiple variables, we'll need to build a custom prototype for each one.  $firstToken already has the
        -            # declaring word.  We're going to store each name in @names, and we're going to use $prototypeStart and
        -            # $prototypeEnd to capture any properties appearing after the list.
        -
        -            my $name;
        -            my @names;
        -            my $hasComma = 0;
        -
        -            $prototypeStart = $prototypeEnd + 1;
        -            $prototypeStartLine = $prototypeEndLine;
        -
        -            for (;;)
        -                {
        -                $self->TryToSkipWhitespace(\$prototypeStart, \$prototypeStartLine);
        -
        -                $name = $self->TryToGetVariableName(\$prototypeStart, \$prototypeStartLine);
        -
        -                if (!defined $name)
        -                    {  return undef;  };
        -
        -                push @names, $name;
        -
        -                $self->TryToSkipWhitespace(\$prototypeStart, \$prototypeStartLine);
        -
        -                # We can have multiple commas in a row.  We can also have trailing commas.  However, the parenthesis must
        -                # not start with a comma or be empty, hence this logic does not appear earlier.
        -                while ($tokens->[$prototypeStart] eq ',')
        -                    {
        -                    $prototypeStart++;
        -                    $self->TryToSkipWhitespace(\$prototypeStart, \$prototypeStartLine);
        -
        -                    $hasComma = 1;
        -                    }
        -
        -                if ($tokens->[$prototypeStart] eq ')')
        -                    {
        -                    $prototypeStart++;
        -                    last;
        -                    }
        -                elsif (!$hasComma)
        -                    {  return undef;  };
        -                };
        -
        -
        -            # Now find the end of the prototype.
        -
        -            $prototypeEnd = $prototypeStart;
        -            $prototypeEndLine = $prototypeStartLine;
        -
        -            while ($prototypeEnd < scalar @$tokens &&
        -                     $tokens->[$prototypeEnd] !~ /^[\;\=]/)
        -                {
        -                $prototypeEnd++;
        -                };
        -
        -
        -            my $prototypePrefix = $firstToken . ' ';
        -            if (defined $type)
        -                {  $prototypePrefix .= $type . ' ';  };
        -
        -            my $prototypeSuffix = ' ' . $self->CreateString($prototypeStart, $prototypeEnd);
        -
        -            foreach $name (@names)
        -                {
        -                my $prototype = $self->NormalizePrototype( $prototypePrefix . $name . $prototypeSuffix );
        -
        -                $self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New(::TOPIC_VARIABLE(), $name,
        -                                                                                                           $self->CurrentScope(), undef,
        -                                                                                                           $prototype,
        -                                                                                                           undef, undef, $prototypeStartLine));
        -                };
        -
        -            $self->SkipRestOfStatement(\$prototypeEnd, \$prototypeEndLine);
        -
        -            $$indexRef = $prototypeEnd;
        -            $$lineNumberRef = $prototypeEndLine;
        -            }
        -
        -        else # no parenthesis
        -            {
        -            my $name = $self->TryToGetVariableName(\$prototypeEnd, \$prototypeEndLine);
        -
        -            if (!defined $name)
        -                {  return undef;  };
        -
        -            while ($prototypeEnd < scalar @$tokens &&
        -                     $tokens->[$prototypeEnd] !~ /^[\;\=]/)
        -                {
        -                $prototypeEnd++;
        -                };
        -
        -            my $prototype = $self->NormalizePrototype( $self->CreateString($prototypeStart, $prototypeEnd) );
        -
        -            $self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New(::TOPIC_VARIABLE(), $name,
        -                                                                                                       $self->CurrentScope(), undef,
        -                                                                                                       $prototype,
        -                                                                                                       undef, undef, $prototypeStartLine));
        -
        -            $self->SkipRestOfStatement(\$prototypeEnd, \$prototypeEndLine);
        -
        -            $$indexRef = $prototypeEnd;
        -            $$lineNumberRef = $prototypeEndLine;
        -            };
        -
        -        return 1;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: TryToGetVariableName
        -#
        -#   Determines if the position is at a variable name, and if so, skips it and returns the name.
        -#
        -sub TryToGetVariableName #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $name;
        -
        -    if ($tokens->[$$indexRef] =~ /^[\$\@\%\*]/)
        -        {
        -        $name .= $tokens->[$$indexRef];
        -        $$indexRef++;
        -
        -        $self->TryToSkipWhitespace($indexRef, $lineNumberRef);
        -
        -        if ($tokens->[$$indexRef] =~ /^[a-z_]/i)
        -            {
        -            $name .= $tokens->[$$indexRef];
        -            $$indexRef++;
        -            }
        -        else
        -            {  return undef;  };
        -        };
        -
        -    return $name;
        -    };
        -
        -
        -#
        -#   Function: TryToGetListOfStrings
        -#
        -#   Attempts to retrieve a list of strings from the current position.  Returns an arrayref of them if any are found, or undef if none.
        -#   It stops the moment it reaches a non-string, so "string1, variable, string2" will only return string1.
        -#
        -#   Supported Syntaxes:
        -#
        -#   - Supports parenthesis.
        -#   - Supports all string forms supported by <TryToSkipString()>.
        -#   - Supports qw() string arrays.
        -#
        -sub TryToGetListOfStrings #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $parenthesis = 0;
        -    my $strings;
        -
        -    while ($$indexRef < scalar @$tokens)
        -        {
        -        # We'll tolerate parenthesis.
        -        if ($tokens->[$$indexRef] eq '(')
        -            {
        -            $$indexRef++;
        -            $parenthesis++;
        -            }
        -        elsif ($tokens->[$$indexRef] eq ')')
        -            {
        -            if ($parenthesis == 0)
        -                {  last;  };
        -
        -            $$indexRef++;
        -            $parenthesis--;
        -            }
        -        elsif ($tokens->[$$indexRef] eq ',')
        -            {
        -            $$indexRef++;
        -            }
        -        else
        -            {
        -            my ($startContent, $endContent);
        -            my $symbolIndex = $$indexRef;
        -
        -            if ($self->TryToSkipString($indexRef, $lineNumberRef, \$startContent, \$endContent))
        -                {
        -                my $content = $self->CreateString($startContent, $endContent);
        -
        -                if (!defined $strings)
        -                    {  $strings = [ ];  };
        -
        -                if (lc($tokens->[$symbolIndex]) eq 'qw')
        -                    {
        -                    $content =~ tr/ \t\n/ /s;
        -                    $content =~ s/^ //;
        -
        -                    my @qwStrings = split(/ /, $content);
        -
        -                    push @$strings, @qwStrings;
        -                    }
        -                else
        -                    {
        -                    push @$strings, $content;
        -                    };
        -                }
        -            else
        -                {  last;  };
        -            };
        -
        -        $self->TryToSkipWhitespace($indexRef, $lineNumberRef);
        -        };
        -
        -    return $strings;
        -    };
        -
        -
        -###############################################################################
        -# Group: Low Level Parsing Functions
        -
        -
        -#
        -#   Function: GenericSkip
        -#
        -#   Advances the position one place through general code.
        -#
        -#   - If the position is on a comment or string, it will skip it completely.
        -#   - If the position is on an opening symbol, it will skip until the past the closing symbol.
        -#   - If the position is on a regexp or quote-like operator, it will skip it completely.
        -#   - If the position is on a backslash, it will skip it and the following token.
        -#   - If the position is on whitespace (including comments), it will skip it completely.
        -#   - Otherwise it skips one token.
        -#
        -#   Parameters:
        -#
        -#       indexRef - A reference to the current index.
        -#       lineNumberRef - A reference to the current line number.
        -#       noRegExps - If set, does not test for regular expressions.
        -#
        -sub GenericSkip #(indexRef, lineNumberRef, noRegExps)
        -    {
        -    my ($self, $indexRef, $lineNumberRef, $noRegExps, $allowStringedClosingParens) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($tokens->[$$indexRef] eq "\\" && $$indexRef + 1 < scalar @$tokens && $tokens->[$$indexRef+1] ne "\n")
        -        {  $$indexRef += 2;  }
        -
        -    # Note that we don't want to count backslashed ()[]{} since they could be in regexps.  Also, ()[] are valid variable names
        -    # when preceded by a string.
        -
        -    # We can ignore the scope stack because we're just skipping everything without parsing, and we need recursion anyway.
        -    elsif ($tokens->[$$indexRef] eq '{' && !$self->IsBackslashed($$indexRef))
        -        {
        -        $$indexRef++;
        -        $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, '}', $noRegExps, $allowStringedClosingParens);
        -        }
        -    elsif ($tokens->[$$indexRef] eq '(' && !$self->IsBackslashed($$indexRef) && !$self->IsStringed($$indexRef))
        -        {
        -        # Temporarily allow stringed closing parenthesis if it looks like we're in an anonymous function declaration with Perl's
        -        # cheap version of prototypes, such as "my $_declare = sub($) {}".
        -        my $tempAllowStringedClosingParens = $allowStringedClosingParens;
        -        if (!$allowStringedClosingParens)
        -        	{
        -        	my $tempIndex = $$indexRef - 1;
        -        	if ($tempIndex >= 0 && $tokens->[$tempIndex] =~ /^[ \t]/)
        -        		{  $tempIndex--;  }
        -        	if ($tempIndex >= 0 && $tokens->[$tempIndex] eq 'sub')
        -        		{  $tempAllowStringedClosingParens = 1;  }
        -        	}
        -
        -        $$indexRef++;
        -
        -        do
        -            {  $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, ')', $noRegExps, $tempAllowStringedClosingParens);  }
        -        while ($$indexRef < scalar @$tokens && $self->IsStringed($$indexRef - 1) && !$tempAllowStringedClosingParens);
        -        }
        -    elsif ($tokens->[$$indexRef] eq '[' && !$self->IsBackslashed($$indexRef) && !$self->IsStringed($$indexRef))
        -        {
        -        $$indexRef++;
        -
        -        do
        -            {  $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, ']', $noRegExps, $allowStringedClosingParens);  }
        -        while ($$indexRef < scalar @$tokens && $self->IsStringed($$indexRef - 1));
        -        }
        -
        -    elsif ($self->TryToSkipWhitespace($indexRef, $lineNumberRef) ||
        -            $self->TryToSkipString($indexRef, $lineNumberRef) ||
        -            $self->TryToSkipHereDocDeclaration($indexRef, $lineNumberRef) ||
        -            (!$noRegExps && $self->TryToSkipRegexp($indexRef, $lineNumberRef) ) )
        -        {
        -        }
        -
        -    else
        -        {  $$indexRef++;  };
        -    };
        -
        -
        -#
        -#   Function: GenericSkipUntilAfter
        -#
        -#   Advances the position via <GenericSkip()> until a specific token is reached and passed.
        -#
        -sub GenericSkipUntilAfter #(indexRef, lineNumberRef, token, noRegExps, allowStringedClosingParens)
        -    {
        -    my ($self, $indexRef, $lineNumberRef, $token, $noRegExps, $allowStringedClosingParens) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    while ($$indexRef < scalar @$tokens && $tokens->[$$indexRef] ne $token)
        -        {  $self->GenericSkip($indexRef, $lineNumberRef, $noRegExps, $allowStringedClosingParens);  };
        -
        -    if ($tokens->[$$indexRef] eq "\n")
        -        {  $$lineNumberRef++;  };
        -    $$indexRef++;
        -    };
        -
        -
        -#
        -#   Function: GenericRegexpSkip
        -#
        -#   Advances the position one place through regexp code.
        -#
        -#   - If the position is on an opening symbol, it will skip until the past the closing symbol.
        -#   - If the position is on a backslash, it will skip it and the following token.
        -#   - If the position is on whitespace (not including comments), it will skip it completely.
        -#   - Otherwise it skips one token.
        -#
        -#   Also differs from <GenericSkip()> in that the parenthesis in $( and $) do count against the scope, where they wouldn't
        -#   normally.
        -#
        -#   Parameters:
        -#
        -#       indexRef - A reference to the current index.
        -#       lineNumberRef - A reference to the current line number.
        -#       inBrackets - Whether we're in brackets or not.  If true, we don't care about matching braces and parenthesis.
        -#
        -sub GenericRegexpSkip #(indexRef, lineNumberRef, inBrackets)
        -    {
        -    my ($self, $indexRef, $lineNumberRef, $inBrackets) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($tokens->[$$indexRef] eq "\\" && $$indexRef + 1 < scalar @$tokens && $tokens->[$$indexRef+1] ne "\n")
        -        {  $$indexRef += 2;  }
        -
        -    # We can ignore the scope stack because we're just skipping everything without parsing, and we need recursion anyway.
        -    elsif ($tokens->[$$indexRef] eq '{' && !$self->IsBackslashed($$indexRef) && !$inBrackets)
        -        {
        -        $$indexRef++;
        -        $self->GenericRegexpSkipUntilAfter($indexRef, $lineNumberRef, '}');
        -        }
        -    elsif ($tokens->[$$indexRef] eq '(' && !$self->IsBackslashed($$indexRef) && !$inBrackets)
        -        {
        -        $$indexRef++;
        -        $self->GenericRegexpSkipUntilAfter($indexRef, $lineNumberRef, ')');
        -        }
        -    elsif ($tokens->[$$indexRef] eq '[' && !$self->IsBackslashed($$indexRef) && !$self->IsStringed($$indexRef))
        -        {
        -        $$indexRef++;
        -
        -        do
        -            {  $self->GenericRegexpSkipUntilAfter($indexRef, $lineNumberRef, ']');  }
        -        while ($$indexRef < scalar @$tokens && $self->IsStringed($$indexRef - 1));
        -        }
        -
        -    elsif ($tokens->[$$indexRef] eq "\n")
        -        {
        -        $$lineNumberRef++;
        -        $$indexRef++;
        -        }
        -
        -    else
        -        {  $$indexRef++;  };
        -    };
        -
        -
        -#
        -#   Function: GenericRegexpSkipUntilAfter
        -#
        -#   Advances the position via <GenericRegexpSkip()> until a specific token is reached and passed.
        -#
        -sub GenericRegexpSkipUntilAfter #(indexRef, lineNumberRef, token)
        -    {
        -    my ($self, $indexRef, $lineNumberRef, $token) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $inBrackets = ( $token eq ']' );
        -
        -    while ($$indexRef < scalar @$tokens && $tokens->[$$indexRef] ne $token)
        -        {  $self->GenericRegexpSkip($indexRef, $lineNumberRef, $inBrackets);  };
        -
        -    if ($tokens->[$$indexRef] eq "\n")
        -        {  $$lineNumberRef++;  };
        -    $$indexRef++;
        -    };
        -
        -
        -#
        -#   Function: SkipRestOfStatement
        -#
        -#   Advances the position via <GenericSkip()> until after the end of the current statement, which is defined as a semicolon or
        -#   a brace group.  Of course, either of those appearing inside parenthesis, a nested brace group, etc. don't count.
        -#
        -sub SkipRestOfStatement #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    while ($$indexRef < scalar @$tokens &&
        -             $tokens->[$$indexRef] ne ';' &&
        -             !($tokens->[$$indexRef] eq '{' && !$self->IsStringed($$indexRef)) )
        -        {
        -        $self->GenericSkip($indexRef, $lineNumberRef);
        -        };
        -
        -    if ($tokens->[$$indexRef] eq ';')
        -        {  $$indexRef++;  }
        -    elsif ($tokens->[$$indexRef] eq '{')
        -        {  $self->GenericSkip($indexRef, $lineNumberRef);  };
        -    };
        -
        -
        -#
        -#   Function: TryToSkipWhitespace
        -#
        -#   If the current position is on whitespace it skips them and returns true.  If there are a number of these in a row, it skips them
        -#   all.
        -#
        -#   Supported Syntax:
        -#
        -#       - Whitespace
        -#       - Line break
        -#       - All comment forms supported by <TryToSkipComment()>
        -#       - Here Doc content
        -#
        -sub TryToSkipWhitespace #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $result;
        -
        -    while ($$indexRef < scalar @$tokens)
        -        {
        -        if ($self->TryToSkipHereDocContent($indexRef, $lineNumberRef) ||
        -            $self->TryToSkipComment($indexRef, $lineNumberRef))
        -            {
        -            $result = 1;
        -            }
        -        elsif ($tokens->[$$indexRef] =~ /^[ \t]/)
        -            {
        -            $$indexRef++;
        -            $result = 1;
        -            }
        -        elsif ($tokens->[$$indexRef] eq "\n")
        -            {
        -            $$indexRef++;
        -            $$lineNumberRef++;
        -            $result = 1;
        -            }
        -        else
        -            {  last;  };
        -        };
        -
        -    return $result;
        -    };
        -
        -
        -#
        -#   Function: TryToSkipComment
        -#   If the current position is on a comment, skip past it and return true.
        -#
        -sub TryToSkipComment #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -
        -    return ( $self->TryToSkipLineComment($indexRef, $lineNumberRef) ||
        -                $self->TryToSkipPODComment($indexRef, $lineNumberRef) );
        -    };
        -
        -
        -#
        -#   Function: TryToSkipLineComment
        -#   If the current position is on a line comment symbol, skip past it and return true.
        -#
        -sub TryToSkipLineComment #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    # Note that $#var is not a comment.
        -    if ($tokens->[$$indexRef] eq '#' && !$self->IsStringed($$indexRef))
        -        {
        -        $self->SkipRestOfLine($indexRef, $lineNumberRef);
        -        return 1;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: TryToSkipPODComment
        -#   If the current position is on a POD comment symbol, skip past it and return true.
        -#
        -sub TryToSkipPODComment #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    # Note that whitespace is not allowed before the equals sign.  It must directly start a line.
        -    if ($tokens->[$$indexRef] eq '=' &&
        -        ( $$indexRef == 0 || $tokens->[$$indexRef - 1] eq "\n" ) &&
        -        $tokens->[$$indexRef + 1] =~ /^[a-z]/i )
        -        {
        -        # Skip until =cut or (NDPODBREAK).  Note that it's theoretically possible for =cut to appear without a prior POD directive.
        -
        -        do
        -            {
        -            if ($tokens->[$$indexRef] eq '=' && lc( $tokens->[$$indexRef + 1] ) eq 'cut')
        -                {
        -                $self->SkipRestOfLine($indexRef, $lineNumberRef);
        -                last;
        -                }
        -            elsif ($tokens->[$$indexRef] eq '(' && $$indexRef + 2 < scalar @$tokens &&
        -                    $tokens->[$$indexRef+1] eq 'NDPODBREAK' && $tokens->[$$indexRef+2] eq ')')
        -                {
        -                $$indexRef += 3;
        -                last;
        -                }
        -            else
        -                {
        -                $self->SkipRestOfLine($indexRef, $lineNumberRef);
        -                };
        -            }
        -        while ($$indexRef < scalar @$tokens);
        -
        -        return 1;
        -        }
        -
        -    # It's also possible that (NDPODBREAK) will appear without any opening pod statement because "=begin nd" and "=cut" will
        -    # still result in one.  We need to pick off the stray (NDPODBREAK).
        -    elsif ($tokens->[$$indexRef] eq '(' && $$indexRef + 2 < scalar @$tokens &&
        -            $tokens->[$$indexRef+1] eq 'NDPODBREAK' && $tokens->[$$indexRef+2] eq ')')
        -        {
        -        $$indexRef += 3;
        -        return 1;
        -        }
        -
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: TryToSkipString
        -#   If the current position is on a string delimiter, skip past the string and return true.
        -#
        -#   Parameters:
        -#
        -#       indexRef - A reference to the index of the position to start at.
        -#       lineNumberRef - A reference to the line number of the position.
        -#       startContentIndexRef - A reference to the variable in which to store the index of the first content token.  May be undef.
        -#       endContentIndexRef - A reference to the variable in which to store the index of the end of the content, which is one past
        -#                                        the last content token.  may be undef.
        -#
        -#   Returns:
        -#
        -#       Whether the position was at a string.  The index, line number, and content index variabls will only be changed if true.
        -#
        -#   Syntax Support:
        -#
        -#       - Supports quotes, apostrophes, backticks, q(), qq(), qx(), and qw().
        -#       - All symbols are supported for the letter forms.
        -#
        -sub TryToSkipString #(indexRef, lineNumberRef, startContentIndexRef, endContentIndexRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef, $startContentIndexRef, $endContentIndexRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    # The three string delimiters.  All three are Perl variables when preceded by a dollar sign.
        -    if (!$self->IsStringed($$indexRef) &&
        -        ( $self->SUPER::TryToSkipString($indexRef, $lineNumberRef, '\'', '\'', $startContentIndexRef, $endContentIndexRef) ||
        -          $self->SUPER::TryToSkipString($indexRef, $lineNumberRef, '"', '"', $startContentIndexRef, $endContentIndexRef) ||
        -          $self->SUPER::TryToSkipString($indexRef, $lineNumberRef, '`', '`', $startContentIndexRef, $endContentIndexRef) ) )
        -        {
        -        return 1;
        -        }
        -    elsif ($tokens->[$$indexRef] =~ /^(?:q|qq|qx|qw)$/i &&
        -            ($$indexRef == 0 || $tokens->[$$indexRef - 1] !~ /^[\$\%\@\*]$/))
        -        {
        -        $$indexRef++;
        -
        -        $self->TryToSkipWhitespace($indexRef, $lineNumberRef);
        -
        -        my $openingSymbol = $tokens->[$$indexRef];
        -        my $closingSymbol;
        -
        -        if ($openingSymbol eq '{')
        -            {  $closingSymbol = '}';  }
        -        elsif ($openingSymbol eq '(')
        -            {  $closingSymbol = ')';  }
        -        elsif ($openingSymbol eq '[')
        -            {  $closingSymbol = ']';  }
        -        elsif ($openingSymbol eq '<')
        -            {  $closingSymbol = '>';  }
        -        else
        -            {  $closingSymbol = $openingSymbol;  };
        -
        -        $self->SUPER::TryToSkipString($indexRef, $lineNumberRef, $openingSymbol, $closingSymbol,
        -                                                      $startContentIndexRef, $endContentIndexRef);
        -
        -        return 1;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: TryToSkipHereDocDeclaration
        -#
        -#   If the current position is on a Here Doc declaration, add its terminators to <hereDocTerminators> and skip it.
        -#
        -#   Syntax Support:
        -#
        -#       - Supports <<EOF
        -#       - Supports << "String" with all string forms supported by <TryToSkipString()>.
        -#
        -sub TryToSkipHereDocDeclaration #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $index = $$indexRef;
        -    my $lineNumber = $$lineNumberRef;
        -
        -    if ($tokens->[$index] eq '<' && $tokens->[$index + 1] eq '<')
        -        {
        -        $index += 2;
        -        my $success;
        -
        -        # No whitespace allowed with the bare word.
        -        if ($tokens->[$index] =~ /^[a-z0-9_]/i)
        -            {
        -            push @hereDocTerminators, [ $tokens->[$index] ];
        -            $index++;
        -            $success = 1;
        -            }
        -        else
        -            {
        -            $self->TryToSkipWhitespace(\$index, \$lineNumber);
        -
        -            my ($contentStart, $contentEnd);
        -            if ($self->TryToSkipString(\$index, \$lineNumber, \$contentStart, \$contentEnd))
        -                {
        -                push @hereDocTerminators, [ @{$tokens}[$contentStart..$contentEnd - 1] ];
        -                $success = 1;
        -                };
        -            };
        -
        -        if ($success)
        -            {
        -            $$indexRef = $index;
        -            $$lineNumberRef = $lineNumber;
        -
        -            return 1;
        -            };
        -        };
        -
        -    return 0;
        -    };
        -
        -
        -#
        -#   Function: TryToSkipHereDocContent
        -#
        -#   If the current position is at the beginning of a line and there are entries in <hereDocTerminators>, skips lines until all the
        -#   terminators are exhausted or we reach the end of the file.
        -#
        -#   Returns:
        -#
        -#       Whether the position was on Here Doc content.
        -#
        -sub TryToSkipHereDocContent #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    # We don't use IsFirstLineToken() because it really needs to be the first line token.  Whitespace is not allowed.
        -    if ($$indexRef > 0 && $tokens->[$$indexRef - 1] eq "\n")
        -        {
        -        my $success = (scalar @hereDocTerminators > 0);
        -
        -        while (scalar @hereDocTerminators && $$indexRef < scalar @$tokens)
        -            {
        -            my $terminatorIndex = 0;
        -
        -            while ($hereDocTerminators[0]->[$terminatorIndex] eq $tokens->[$$indexRef])
        -                {
        -                $terminatorIndex++;
        -                $$indexRef++;
        -                };
        -
        -            if ($terminatorIndex == scalar @{$hereDocTerminators[0]} &&
        -                ($tokens->[$$indexRef] eq "\n" || ($tokens->[$$indexRef] =~ /^[ \t]/ && $tokens->[$$indexRef + 1] eq "\n")) )
        -                {
        -                shift @hereDocTerminators;
        -                $$indexRef++;
        -                $$lineNumberRef++;
        -                }
        -            else
        -                {  $self->SkipRestOfLine($indexRef, $lineNumberRef);  };
        -            };
        -
        -        return $success;
        -        }
        -
        -    else
        -        {  return 0;  };
        -    };
        -
        -
        -#
        -#   Function: TryToSkipRegexp
        -#   If the current position is on a regular expression or a quote-like operator, skip past it and return true.
        -#
        -#   Syntax Support:
        -#
        -#       - Supports //, ??, m//, qr//, s///, tr///, and y///.
        -#       - All symbols are supported for the letter forms.
        -#       - ?? is *not* supported because it could cause problems with ?: statements.  The generic parser has a good chance of
        -#         successfully stumbling through a regex, whereas the regex code will almost certainly see the rest of the file as part of it.
        -#
        -sub TryToSkipRegexp #(indexRef, lineNumberRef)
        -    {
        -    my ($self, $indexRef, $lineNumberRef) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    my $isRegexp;
        -
        -    # If it's a supported character sequence that's not a variable (ex $qr) or package (ex a::tr)...
        -    if ($tokens->[$$indexRef] =~ /^(?:m|qr|s|tr|y)$/i &&
        -         ($$indexRef == 0 || $tokens->[$$indexRef - 1] !~ /^[\$\%\@\*\-\>\:]$/) )
        -        {  $isRegexp = 1;  }
        -
        -    elsif ($tokens->[$$indexRef] eq '/' && !$self->IsStringed($$indexRef))
        -        {
        -        # This is a bit of a hack.  If we find a random slash, it could be a divide operator or a bare regexp.  Find the first previous
        -        # non-whitespace token and if it's text, a closing brace, or a string, assume it's a divide operator.  (Strings don't make
        -        # much pratical sense there but a regexp would be impossible.)  Otherwise assume it's a regexp.
        -
        -        # We make a special consideration for split() appearing without parenthesis.  If the previous token is split and it's not a
        -        # variable, assume it is a regexp even though it fails the above test.
        -
        -        my $index = $$indexRef - 1;
        -
        -        while ($index >= 0 && $tokens->[$index] =~ /^(?: |\t|\n)/)
        -            {  $index--;  };
        -
        -        if ($index < 0 || $tokens->[$index] !~ /^[a-zA-Z0-9_\)\]\}\'\"\`]/ ||
        -            ($tokens->[$index] =~ /^split|grep$/ && $index > 0 && $tokens->[$index-1] !~ /^[\$\%\@\*]$/) )
        -            {  $isRegexp = 1;  };
        -        };
        -
        -    if ($isRegexp)
        -        {
        -        my $operator = lc($tokens->[$$indexRef]);
        -        my $index = $$indexRef;
        -        my $lineNumber = $$lineNumberRef;
        -
        -        if ($operator =~ /^[\?\/]/)
        -            {  $operator = 'm';  }
        -        else
        -            {
        -            $index++;
        -
        -            # Believe it or not, s#...# is allowed.  We can't pass over number signs here.
        -            if ($tokens->[$index] ne '#')
        -                {  $self->TryToSkipWhitespace(\$index, \$lineNumber);  };
        -            };
        -
        -        if ($tokens->[$index] =~ /^\w/)
        -            {  return undef;  };
        -        if ($tokens->[$index] eq '=' && $tokens->[$index+1] eq '>')
        -        	{  return undef;  };
        -
        -        my $openingSymbol = $tokens->[$index];
        -        my $closingSymbol;
        -
        -        if ($openingSymbol eq '{')
        -            {  $closingSymbol = '}';  }
        -        elsif ($openingSymbol eq '(')
        -            {  $closingSymbol = ')';  }
        -        elsif ($openingSymbol eq '[')
        -            {  $closingSymbol = ']';  }
        -        elsif ($openingSymbol eq '<')
        -            {  $closingSymbol = '>';  }
        -        else
        -            {  $closingSymbol = $openingSymbol;  };
        -
        -        $index++;
        -
        -        $self->GenericRegexpSkipUntilAfter(\$index, \$lineNumber, $closingSymbol);
        -
        -        $$indexRef = $index;
        -        $$lineNumberRef = $lineNumber;
        -
        -        if ($operator =~ /^(?:s|tr|y)$/)
        -            {
        -            if ($openingSymbol ne $closingSymbol)
        -                {
        -                $self->TryToSkipWhitespace($indexRef, $lineNumberRef);
        -
        -                $openingSymbol = $tokens->[$index];
        -
        -                if ($openingSymbol eq '{')
        -                    {  $closingSymbol = '}';  }
        -                elsif ($openingSymbol eq '(')
        -                    {  $closingSymbol = ')';  }
        -                elsif ($openingSymbol eq '[')
        -                    {  $closingSymbol = ']';  }
        -                elsif ($openingSymbol eq '<')
        -                    {  $closingSymbol = '>';  }
        -                else
        -                    {  $closingSymbol = $openingSymbol;  };
        -
        -                $$indexRef++;
        -                };
        -
        -            if ($operator eq 's')
        -                {
        -                $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, $closingSymbol, 1);
        -                }
        -            else # ($operator eq 'tr' || $operator eq 'y')
        -                {
        -                while ($$indexRef < scalar @$tokens &&
        -                          ($tokens->[$$indexRef] ne $closingSymbol || $self->IsBackslashed($$indexRef)) )
        -                    {
        -                    if ($tokens->[$$indexRef] eq "\n")
        -                        {  $$lineNumberRef++;  };
        -                    $$indexRef++;
        -                    };
        -
        -                $$indexRef++;
        -                };
        -            };
        -
        -        # We want to skip any letters after the regexp.  Otherwise something like tr/a/b/s; could have the trailing s; interpreted
        -        # as another regexp.  Whitespace is not allowed between the closing symbol and the letters.
        -
        -        if ($tokens->[$$indexRef] =~ /^[a-z]/i)
        -            {  $$indexRef++;  };
        -
        -        return 1;
        -        };
        -
        -    return undef;
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -
        -#
        -#   Function: IsStringed
        -#
        -#   Returns whether the position is after a string (dollar sign) character.  Returns false if it's preceded by two dollar signs so
        -#   "if ($x == $$)" doesn't skip the closing parenthesis as stringed.
        -#
        -#   Parameters:
        -#
        -#       index - The index of the postition.
        -#
        -sub IsStringed #(index)
        -    {
        -    my ($self, $index) = @_;
        -    my $tokens = $self->Tokens();
        -
        -    if ($index > 0 && $tokens->[$index - 1] eq '$' && !($index > 1 && $tokens->[$index - 2] eq '$'))
        -        {  return 1;  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Prototype.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages/Prototype.pm
        deleted file mode 100644
        index b4d5fc86f..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Prototype.pm
        +++ /dev/null
        @@ -1,93 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Languages::Prototype
        -#
        -###############################################################################
        -#
        -#   A data class for storing parsed prototypes.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -use NaturalDocs::Languages::Prototype::Parameter;
        -
        -
        -package NaturalDocs::Languages::Prototype;
        -
        -use NaturalDocs::DefineMembers 'BEFORE_PARAMETERS', 'BeforeParameters()', 'SetBeforeParameters()',
        -                                                 'AFTER_PARAMETERS', 'AfterParameters()', 'SetAfterParameters()',
        -                                                 'PARAMETERS', 'Parameters()';
        -# Dependency: New(), constant order, no parents.
        -
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new prototype object.
        -#
        -#   Parameters:
        -#
        -#       beforeParameters - The part of the prototype before the parameter list.
        -#       afterParameters - The part of the prototype after the parameter list.
        -#
        -#   You cannot set the parameters from here.  Use <AddParameter()>.
        -#
        -sub New #(beforeParameters, afterParameters)
        -    {
        -    my ($package, @params) = @_;
        -
        -    # Dependency: Constant order, no parents.
        -
        -    my $object = [ @params ];
        -    bless $object, $package;
        -
        -    return $object;
        -    };
        -
        -
        -#
        -#   Functions: Members
        -#
        -#   BeforeParameters - Returns the part of the prototype before the parameter list.  If there is no parameter list, this will be the
        -#                                only thing that returns content.
        -#   SetBeforeParameters - Replaces the part of the prototype before the parameter list.
        -#   AfterParameters - Returns the part of the prototype after the parameter list, if any.
        -#   SetAfterParameters - Replaces the part of the prototype after the parameter list.
        -#   Parameters - Returns the parameter list as an arrayref of <NaturalDocs::Languages::Prototype::Parameters>, or undef if none.
        -#
        -
        -#
        -#   Function: AddParameter
        -#
        -#   Adds a <NaturalDocs::Languages::Prototype::Parameter> to the list.
        -#
        -sub AddParameter #(parameter)
        -    {
        -    my ($self, $parameter) = @_;
        -
        -    if (!defined $self->[PARAMETERS])
        -        {  $self->[PARAMETERS] = [ ];  };
        -
        -    push @{$self->[PARAMETERS]}, $parameter;
        -    };
        -
        -
        -#
        -#   Function: OnlyBeforeParameters
        -#
        -#   Returns whether <BeforeParameters()> is the only thing set.
        -#
        -sub OnlyBeforeParameters
        -    {
        -    my $self = shift;
        -    return (!defined $self->[PARAMETERS] && !defined $self->[AFTER_PARAMETERS]);
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Prototype/Parameter.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages/Prototype/Parameter.pm
        deleted file mode 100644
        index 41b5bce54..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Prototype/Parameter.pm
        +++ /dev/null
        @@ -1,88 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Languages::Prototype::Parameter
        -#
        -###############################################################################
        -#
        -#   A data class for storing parsed prototype parameters.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Languages::Prototype::Parameter;
        -
        -use NaturalDocs::DefineMembers 'TYPE', 'Type()', 'SetType()',
        -                                                 'TYPE_PREFIX', 'TypePrefix()', 'SetTypePrefix()',
        -                                                 'NAME', 'Name()', 'SetName()',
        -                                                 'NAME_PREFIX', 'NamePrefix()', 'SetNamePrefix()',
        -                                                 'DEFAULT_VALUE', 'DefaultValue()', 'SetDefaultValue()',
        -                                                 'DEFAULT_VALUE_PREFIX', 'DefaultValuePrefix()', 'SetDefaultValuePrefix()';
        -# Dependency: New() depends on the order of these constants and that they don't inherit from another class.
        -
        -
        -#
        -#   Constants: Members
        -#
        -#   The object is implemented as a blessed arrayref, with the following constants as its indexes.
        -#
        -#       TYPE - The parameter type, if any.
        -#       TYPE_PREFIX - The parameter type prefix which should be aligned separately, if any.
        -#       NAME - The parameter name.
        -#       NAME_PREFIX - The parameter name prefix which should be aligned separately, if any.
        -#       DEFAULT_VALUE - The default value expression, if any.
        -#       DEFAULT_VALUE_PREFIX - The default value prefix which should be aligned separately, if any.
        -#
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new prototype object.
        -#
        -#   Parameters:
        -#
        -#       type - The parameter type, if any.
        -#       typePrefix - The parameter type prefix which should be aligned separately, if any.
        -#       name - The parameter name.
        -#       namePrefix - The parameter name prefix which should be aligned separately, if any.
        -#       defaultValue - The default value expression, if any.
        -#       defaultValuePrefix - The default value prefix which should be aligned separately, if any.
        -#
        -sub New #(type, typePrefix, name, namePrefix, defaultValue, defaultValuePrefix)
        -    {
        -    my ($package, @params) = @_;
        -
        -    # Dependency: This depends on the order of the parameters being the same as the order of the constants, and that the
        -    # constants don't inherit from another class.
        -
        -    my $object = [ @params ];
        -    bless $object, $package;
        -
        -    return $object;
        -    };
        -
        -
        -#
        -#   Functions: Members
        -#
        -#   Type - The parameter type, if any.
        -#   SetType - Replaces the parameter type.
        -#   TypePrefix - The parameter type prefix, which should be aligned separately, if any.
        -#   SetTypePrefix - Replaces the parameter type prefix.
        -#   Name - The parameter name.
        -#   SetName - Replaces the parameter name.
        -#   NamePrefix - The parameter name prefix, which should be aligned separately, if any.
        -#   SetNamePrefix - Replaces the parameter name prefix.
        -#   DefaultValue - The default value expression, if any.
        -#   SetDefaultValue - Replaces the default value expression.
        -#   DefaultValuePrefix - The default value prefix, which should be aligned separately, if any.
        -#   SetDefaultValuePrefix - Replaces the default value prefix.
        -#
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Simple.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages/Simple.pm
        deleted file mode 100644
        index 6dfacd86a..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Simple.pm
        +++ /dev/null
        @@ -1,487 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Languages::Simple
        -#
        -###############################################################################
        -#
        -#   A class containing the characteristics of a particular programming language for basic support within Natural Docs.
        -#   Also serves as a base class for languages that break from general conventions, such as not having parameter lists use
        -#   parenthesis and commas.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Languages::Simple;
        -
        -use base 'NaturalDocs::Languages::Base';
        -use base 'Exporter';
        -
        -our @EXPORT = ( 'ENDER_ACCEPT', 'ENDER_IGNORE', 'ENDER_ACCEPT_AND_CONTINUE', 'ENDER_REVERT_TO_ACCEPTED' );
        -
        -
        -use NaturalDocs::DefineMembers 'LINE_COMMENT_SYMBOLS', 'LineCommentSymbols()', 'SetLineCommentSymbols() duparrayref',
        -                                                 'BLOCK_COMMENT_SYMBOLS', 'BlockCommentSymbols()',
        -                                                                                              'SetBlockCommentSymbols() duparrayref',
        -                                                 'PROTOTYPE_ENDERS',
        -                                                 'LINE_EXTENDER', 'LineExtender()', 'SetLineExtender()',
        -                                                 'PACKAGE_SEPARATOR', 'PackageSeparator()',
        -                                                 'PACKAGE_SEPARATOR_WAS_SET', 'PackageSeparatorWasSet()',
        -                                                 'ENUM_VALUES', 'EnumValues()',
        -                                                 'ENUM_VALUES_WAS_SET', 'EnumValuesWasSet()';
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -#   Parameters:
        -#
        -#       name - The name of the language.
        -#
        -sub New #(name)
        -    {
        -    my ($selfPackage, $name) = @_;
        -
        -    my $object = $selfPackage->SUPER::New($name);
        -
        -    $object->[ENUM_VALUES] = ::ENUM_GLOBAL();
        -    $object->[PACKAGE_SEPARATOR] = '.';
        -
        -    return $object;
        -    };
        -
        -
        -#
        -#   Functions: Members
        -#
        -#   LineCommentSymbols - Returns an arrayref of symbols that start a line comment, or undef if none.
        -#   SetLineCommentSymbols - Replaces the arrayref of symbols that start a line comment.
        -#   BlockCommentSymbols - Returns an arrayref of start/end symbol pairs that specify a block comment, or undef if none.  Pairs
        -#                                        are specified with two consecutive array entries.
        -#   SetBlockCommentSymbols - Replaces the arrayref of start/end symbol pairs that specify a block comment.  Pairs are
        -#                                             specified with two consecutive array entries.
        -#   LineExtender - Returns the symbol to ignore a line break in languages where line breaks are significant.
        -#   SetLineExtender - Replaces the symbol to ignore a line break in languages where line breaks are significant.
        -#   PackageSeparator - Returns the package separator symbol.
        -#   PackageSeparatorWasSet - Returns whether the package separator symbol was ever changed from the default.
        -#
        -
        -#
        -#   Function: SetPackageSeparator
        -#   Replaces the language's package separator string.
        -#
        -sub SetPackageSeparator #(separator)
        -    {
        -    my ($self, $separator) = @_;
        -    $self->[PACKAGE_SEPARATOR] = $separator;
        -    $self->[PACKAGE_SEPARATOR_WAS_SET] = 1;
        -    };
        -
        -
        -#
        -#   Functions: Members
        -#
        -#   EnumValues - Returns the <EnumValuesType> that describes how the language handles enums.
        -#   EnumValuesWasSet - Returns whether <EnumValues> was ever changed from the default.
        -
        -
        -#
        -#   Function: SetEnumValues
        -#   Replaces the <EnumValuesType> that describes how the language handles enums.
        -#
        -sub SetEnumValues #(EnumValuesType newBehavior)
        -    {
        -    my ($self, $behavior) = @_;
        -    $self->[ENUM_VALUES] = $behavior;
        -    $self->[ENUM_VALUES_WAS_SET] = 1;
        -    };
        -
        -
        -#
        -#   Function: PrototypeEndersFor
        -#
        -#   Returns an arrayref of prototype ender symbols for the passed <TopicType>, or undef if none.
        -#
        -sub PrototypeEndersFor #(type)
        -    {
        -    my ($self, $type) = @_;
        -
        -    if (defined $self->[PROTOTYPE_ENDERS])
        -        {  return $self->[PROTOTYPE_ENDERS]->{$type};  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: SetPrototypeEndersFor
        -#
        -#   Replaces the arrayref of prototype ender symbols for the passed <TopicType>.
        -#
        -sub SetPrototypeEndersFor #(type, enders)
        -    {
        -    my ($self, $type, $enders) = @_;
        -
        -    if (!defined $self->[PROTOTYPE_ENDERS])
        -        {  $self->[PROTOTYPE_ENDERS] = { };  };
        -
        -    if (!defined $enders)
        -        {  delete $self->[PROTOTYPE_ENDERS]->{$type};  }
        -    else
        -        {
        -        $self->[PROTOTYPE_ENDERS]->{$type} = [ @$enders ];
        -        };
        -    };
        -
        -
        -
        -
        -###############################################################################
        -# Group: Parsing Functions
        -
        -
        -#
        -#   Function: ParseFile
        -#
        -#   Parses the passed source file, sending comments acceptable for documentation to <NaturalDocs::Parser->OnComment()>
        -#   and all other sections to <OnCode()>.
        -#
        -#   Parameters:
        -#
        -#       sourceFile - The <FileName> of the source file to parse.
        -#       topicList - A reference to the list of <NaturalDocs::Parser::ParsedTopics> being built by the file.
        -#
        -#   Returns:
        -#
        -#       Since this class cannot automatically document the code or generate a scope record, it always returns ( undef, undef ).
        -#
        -sub ParseFile #(sourceFile, topicsList)
        -    {
        -    my ($self, $sourceFile, $topicsList) = @_;
        -
        -    open(SOURCEFILEHANDLE, '<' . $sourceFile)
        -        or die "Couldn't open input file " . $sourceFile . "\n";
        -
        -    my $lineReader = NaturalDocs::LineReader->New(\*SOURCEFILEHANDLE);
        -
        -    my @commentLines;
        -    my @codeLines;
        -    my $lastCommentTopicCount = 0;
        -
        -    if ($self->Name() eq 'Text File')
        -        {
        -        @commentLines = $lineReader->GetAll();
        -        NaturalDocs::Parser->OnComment(\@commentLines, 1);
        -        }
        -
        -    else
        -        {
        -        my $line = $lineReader->Get();
        -        my $lineNumber = 1;
        -
        -        while (defined $line)
        -            {
        -            my $originalLine = $line;
        -
        -
        -            # Retrieve multiline comments.  This leaves $line at the next line.
        -            # We check for multiline comments before single line comments because in Lua the symbols are --[[ and --.
        -
        -            if (my $closingSymbol = $self->StripOpeningBlockSymbols(\$line, $self->BlockCommentSymbols()))
        -                {
        -                # Note that it is possible for a multiline comment to start correctly but not end so.  We want those comments to stay in
        -                # the code.  For example, look at this prototype with this splint annotation:
        -                #
        -                # int get_array(integer_t id,
        -                #                    /*@out@*/ array_t array);
        -                #
        -                # The annotation starts correctly but doesn't end so because it is followed by code on the same line.
        -
        -                my $lineRemainder;
        -
        -                for (;;)
        -                    {
        -                    $lineRemainder = $self->StripClosingSymbol(\$line, $closingSymbol);
        -
        -                    push @commentLines, $line;
        -
        -                    #  If we found an end comment symbol...
        -                    if (defined $lineRemainder)
        -                        {  last;  };
        -
        -                    $line = $lineReader->Get();
        -
        -                    if (!defined $line)
        -                        {  last;  };
        -                    };
        -
        -                if ($lineRemainder !~ /^[ \t]*$/)
        -                    {
        -                    # If there was something past the closing symbol this wasn't an acceptable comment, so move the lines to code.
        -                    push @codeLines, @commentLines;
        -                    @commentLines = ( );
        -                    };
        -
        -                $line = $lineReader->Get();
        -                }
        -
        -
        -            # Retrieve single line comments.  This leaves $line at the next line.
        -
        -            elsif ($self->StripOpeningSymbols(\$line, $self->LineCommentSymbols()))
        -                {
        -                do
        -                    {
        -                    push @commentLines, $line;
        -                    $line = $lineReader->Get();
        -
        -                    if (!defined $line)
        -                        {  goto EndDo;  };
        -                    }
        -                while ($self->StripOpeningSymbols(\$line, $self->LineCommentSymbols()));
        -
        -                EndDo:  # I hate Perl sometimes.
        -                }
        -
        -
        -            # Otherwise just add it to the code.
        -
        -            else
        -                {
        -                push @codeLines, $line;
        -                $line = $lineReader->Get();
        -                };
        -
        -
        -            # If there were comments, send them to Parser->OnComment().
        -
        -            if (scalar @commentLines)
        -                {
        -                # First process any code lines before the comment.
        -                if (scalar @codeLines)
        -                    {
        -                    $self->OnCode(\@codeLines, $lineNumber, $topicsList, $lastCommentTopicCount);
        -                    $lineNumber += scalar @codeLines;
        -                    @codeLines = ( );
        -                    };
        -
        -                $lastCommentTopicCount = NaturalDocs::Parser->OnComment(\@commentLines, $lineNumber);
        -                $lineNumber += scalar @commentLines;
        -                @commentLines = ( );
        -                };
        -
        -            };  # while (defined $line)
        -
        -
        -        # Clean up any remaining code.
        -        if (scalar @codeLines)
        -            {
        -            $self->OnCode(\@codeLines, $lineNumber, $topicsList, $lastCommentTopicCount);
        -            @codeLines = ( );
        -            };
        -
        -        };
        -
        -    close(SOURCEFILEHANDLE);
        -
        -    return ( undef, undef );
        -    };
        -
        -
        -#
        -#   Function: OnCode
        -#
        -#   Called whenever a section of code is encountered by the parser.  Is used to find the prototype of the last topic created.
        -#
        -#   Parameters:
        -#
        -#       codeLines - The source code as an arrayref of lines.
        -#       codeLineNumber - The line number of the first line of code.
        -#       topicList - A reference to the list of <NaturalDocs::Parser::ParsedTopics> being built by the file.
        -#       lastCommentTopicCount - The number of Natural Docs topics that were created by the last comment.
        -#
        -sub OnCode #(codeLines, codeLineNumber, topicList, lastCommentTopicCount)
        -    {
        -    my ($self, $codeLines, $codeLineNumber, $topicList, $lastCommentTopicCount) = @_;
        -
        -    if ($lastCommentTopicCount && defined $self->PrototypeEndersFor($topicList->[-1]->Type()))
        -        {
        -        my $lineIndex = 0;
        -        my $prototype;
        -
        -        # Skip all blank lines before a prototype.
        -        while ($lineIndex < scalar @$codeLines && $codeLines->[$lineIndex] =~ /^[ \t]*$/)
        -            {  $lineIndex++;  };
        -
        -        my @tokens;
        -        my $tokenIndex = 0;
        -
        -        my @brackets;
        -        my $enders = $self->PrototypeEndersFor($topicList->[-1]->Type());
        -
        -        # Add prototype lines until we reach the end of the prototype or the end of the code lines.
        -        while ($lineIndex < scalar @$codeLines)
        -            {
        -            my $line = $self->RemoveLineExtender($codeLines->[$lineIndex] . "\n");
        -
        -            push @tokens, $line =~ /([^\(\)\[\]\{\}\<\>]+|.)/g;
        -
        -            while ($tokenIndex < scalar @tokens)
        -                {
        -                # If we're not inside brackets, check for ender symbols.
        -                if (!scalar @brackets)
        -                    {
        -                    my $startingIndex = 0;
        -                    my $testPrototype;
        -
        -                    for (;;)
        -                        {
        -                        my ($enderIndex, $ender) = ::FindFirstSymbol($tokens[$tokenIndex], $enders, $startingIndex);
        -
        -                        if ($enderIndex == -1)
        -                            {  last;  }
        -                        else
        -                            {
        -                            # We do this here so we don't duplicate prototype for every single token.  Just the first time an ender symbol
        -                            # is found in one.
        -                            if (!defined $testPrototype)
        -                                {  $testPrototype = $prototype;  };
        -
        -                            $testPrototype .= substr($tokens[$tokenIndex], $startingIndex, $enderIndex - $startingIndex);
        -
        -                            my $enderResult;
        -
        -                            # If the ender is all text and the character preceding or following it is as well, ignore it.
        -                            if ($ender =~ /^[a-z0-9]+$/i &&
        -                                ( ($enderIndex > 0 && substr($tokens[$tokenIndex], $enderIndex - 1, 1) =~ /^[a-z0-9_]$/i) ||
        -                                   substr($tokens[$tokenIndex], $enderIndex + length($ender), 1) =~ /^[a-z0-9_]$/i ) )
        -                                {  $enderResult = ENDER_IGNORE();  }
        -                            else
        -                                {  $enderResult = $self->OnPrototypeEnd($topicList->[-1]->Type(), \$testPrototype, $ender);  }
        -
        -                            if ($enderResult == ENDER_IGNORE())
        -                                {
        -                                $testPrototype .= $ender;
        -                                $startingIndex = $enderIndex + length($ender);
        -                                }
        -                            elsif ($enderResult == ENDER_REVERT_TO_ACCEPTED())
        -                                {
        -                                return;
        -                                }
        -                            else # ENDER_ACCEPT || ENDER_ACCEPT_AND_CONTINUE
        -                                {
        -                                my $titleInPrototype = $topicList->[-1]->Title();
        -
        -                                # Strip parenthesis so Function(2) and Function(int, int) will still match Function(anything).
        -                                $titleInPrototype =~ s/[\t ]*\([^\(]*$//;
        -
        -                                if (index($testPrototype, $titleInPrototype) != -1)
        -                                    {
        -                                    $topicList->[-1]->SetPrototype( $self->NormalizePrototype($testPrototype) );
        -                                    };
        -
        -                                if ($enderResult == ENDER_ACCEPT())
        -                                    {  return;  }
        -                                else # ENDER_ACCEPT_AND_CONTINUE
        -                                    {
        -                                    $testPrototype .= $ender;
        -                                    $startingIndex = $enderIndex + length($ender);
        -                                    };
        -                                };
        -                            };
        -                        };
        -                    }
        -
        -                # If we are inside brackets, check for closing symbols.
        -                elsif ( ($tokens[$tokenIndex] eq ')' && $brackets[-1] eq '(') ||
        -                         ($tokens[$tokenIndex] eq ']' && $brackets[-1] eq '[') ||
        -                         ($tokens[$tokenIndex] eq '}' && $brackets[-1] eq '{') ||
        -                         ($tokens[$tokenIndex] eq '>' && $brackets[-1] eq '<') )
        -                    {
        -                    pop @brackets;
        -                    };
        -
        -                # Check for opening brackets.
        -				if ($tokens[$tokenIndex] =~ /^[\(\[\{]$/ ||
        -				    ($tokens[$tokenIndex] eq "<" && $tokens[$tokenIndex-1] !~ /operator[ \t]*$/) )
        -	                {
        -                    push @brackets, $tokens[$tokenIndex];
        -                    };
        -
        -                $prototype .= $tokens[$tokenIndex];
        -                $tokenIndex++;
        -                };
        -
        -            $lineIndex++;
        -            };
        -
        -        # If we got out of that while loop by running out of lines, there was no prototype.
        -        };
        -    };
        -
        -
        -use constant ENDER_ACCEPT => 1;
        -use constant ENDER_IGNORE => 2;
        -use constant ENDER_ACCEPT_AND_CONTINUE => 3;
        -use constant ENDER_REVERT_TO_ACCEPTED => 4;
        -
        -#
        -#   Function: OnPrototypeEnd
        -#
        -#   Called whenever the end of a prototype is found so that there's a chance for derived classes to mark false positives.
        -#
        -#   Parameters:
        -#
        -#       type - The <TopicType> of the prototype.
        -#       prototypeRef - A reference to the prototype so far, minus the ender in dispute.
        -#       ender - The ender symbol.
        -#
        -#   Returns:
        -#
        -#       ENDER_ACCEPT - The ender is accepted and the prototype is finished.
        -#       ENDER_IGNORE - The ender is rejected and parsing should continue.  Note that the prototype will be rejected as a whole
        -#                                  if all enders are ignored before reaching the end of the code.
        -#       ENDER_ACCEPT_AND_CONTINUE - The ender is accepted so the prototype may stand as is.  However, the prototype might
        -#                                                          also continue on so continue parsing.  If there is no accepted ender between here and
        -#                                                          the end of the code this version will be accepted instead.
        -#       ENDER_REVERT_TO_ACCEPTED - The expedition from ENDER_ACCEPT_AND_CONTINUE failed.  Use the last accepted
        -#                                                        version and end parsing.
        -#
        -sub OnPrototypeEnd #(type, prototypeRef, ender)
        -    {
        -    return ENDER_ACCEPT();
        -    };
        -
        -
        -#
        -#   Function: RemoveLineExtender
        -#
        -#   If the passed line has a line extender, returns it without the extender or the line break that follows.  If it doesn't, or there are
        -#   no line extenders defined, returns the passed line unchanged.
        -#
        -sub RemoveLineExtender #(line)
        -    {
        -    my ($self, $line) = @_;
        -
        -    if (defined $self->LineExtender())
        -        {
        -        my $lineExtenderIndex = rindex($line, $self->LineExtender());
        -
        -        if ($lineExtenderIndex != -1 &&
        -            substr($line, $lineExtenderIndex + length($self->LineExtender())) =~ /^[ \t]*\n$/)
        -            {
        -            $line = substr($line, 0, $lineExtenderIndex) . ' ';
        -            };
        -        };
        -
        -    return $line;
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Tcl.pm b/vendor/naturaldocs/Modules/NaturalDocs/Languages/Tcl.pm
        deleted file mode 100644
        index fde2a190a..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Languages/Tcl.pm
        +++ /dev/null
        @@ -1,220 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Languages::Tcl
        -#
        -###############################################################################
        -#
        -#   A subclass to handle the language variations of Tcl.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Languages::Tcl;
        -
        -use base 'NaturalDocs::Languages::Simple';
        -
        -
        -#
        -#   bool: pastFirstBrace
        -#
        -#   Whether we've past the first brace in a function prototype or not.
        -#
        -my $pastFirstBrace;
        -
        -
        -#
        -#   Function: OnCode
        -#
        -#   This is just overridden to reset <pastFirstBrace>.
        -#
        -sub OnCode #(...)
        -    {
        -    my ($self, @params) = @_;
        -
        -    $pastFirstBrace = 0;
        -
        -    return $self->SUPER::OnCode(@params);
        -    };
        -
        -
        -#
        -#   Function: OnPrototypeEnd
        -#
        -#   Tcl's function syntax is shown below.
        -#
        -#   > proc [name] { [params] } { [code] }
        -#
        -#   The opening brace is one of the prototype enders.  We need to allow the first opening brace because it contains the
        -#   parameters.
        -#
        -#   Also, the parameters may have braces within them.  I've seen one that used { seconds 20 } as a parameter.
        -#
        -#   Parameters:
        -#
        -#       type - The <TopicType> of the prototype.
        -#       prototypeRef - A reference to the prototype so far, minus the ender in dispute.
        -#       ender - The ender symbol.
        -#
        -#   Returns:
        -#
        -#       ENDER_ACCEPT - The ender is accepted and the prototype is finished.
        -#       ENDER_IGNORE - The ender is rejected and parsing should continue.  Note that the prototype will be rejected as a whole
        -#                                  if all enders are ignored before reaching the end of the code.
        -#       ENDER_ACCEPT_AND_CONTINUE - The ender is accepted so the prototype may stand as is.  However, the prototype might
        -#                                                          also continue on so continue parsing.  If there is no accepted ender between here and
        -#                                                          the end of the code this version will be accepted instead.
        -#       ENDER_REVERT_TO_ACCEPTED - The expedition from ENDER_ACCEPT_AND_CONTINUE failed.  Use the last accepted
        -#                                                        version and end parsing.
        -#
        -sub OnPrototypeEnd #(type, prototypeRef, ender)
        -    {
        -    my ($self, $type, $prototypeRef, $ender) = @_;
        -
        -    if ($type eq ::TOPIC_FUNCTION() && $ender eq '{' && !$pastFirstBrace)
        -        {
        -        $pastFirstBrace = 1;
        -        return ::ENDER_IGNORE();
        -        }
        -    else
        -        {  return ::ENDER_ACCEPT();  };
        -    };
        -
        -
        -#
        -#   Function: ParsePrototype
        -#
        -#   Parses the prototype and returns it as a <NaturalDocs::Languages::Prototype> object.
        -#
        -#   Parameters:
        -#
        -#       type - The <TopicType>.
        -#       prototype - The text prototype.
        -#
        -#   Returns:
        -#
        -#       A <NaturalDocs::Languages::Prototype> object.
        -#
        -sub ParsePrototype #(type, prototype)
        -    {
        -    my ($self, $type, $prototype) = @_;
        -
        -    if ($type ne ::TOPIC_FUNCTION())
        -        {
        -        my $object = NaturalDocs::Languages::Prototype->New($prototype);
        -        return $object;
        -        };
        -
        -
        -    # Parse the parameters out of the prototype.
        -
        -    my @tokens = $prototype =~ /([^\{\}\ ]+|.)/g;
        -
        -    my $parameter;
        -    my @parameterLines;
        -
        -    my $braceLevel = 0;
        -
        -    my ($beforeParameters, $afterParameters, $finishedParameters);
        -
        -    foreach my $token (@tokens)
        -        {
        -        if ($finishedParameters)
        -            {  $afterParameters .= $token;  }
        -
        -        elsif ($token eq '{')
        -            {
        -            if ($braceLevel == 0)
        -                {  $beforeParameters .= $token;  }
        -
        -            else # braceLevel > 0
        -                {  $parameter .= $token;   };
        -
        -            $braceLevel++;
        -            }
        -
        -        elsif ($token eq '}')
        -            {
        -            if ($braceLevel == 1)
        -                {
        -                if ($parameter && $parameter ne ' ')
        -                    {  push @parameterLines, $parameter;  };
        -
        -                $finishedParameters = 1;
        -                $afterParameters .= $token;
        -
        -                $braceLevel--;
        -                }
        -            elsif ($braceLevel > 1)
        -                {
        -                $parameter .= $token;
        -                $braceLevel--;
        -                };
        -            }
        -
        -        elsif ($token eq ' ')
        -            {
        -            if ($braceLevel == 1)
        -                {
        -                if ($parameter)
        -                    {  push @parameterLines, $parameter;  };
        -
        -                $parameter = undef;
        -                }
        -            elsif ($braceLevel > 1)
        -                {
        -                $parameter .= $token;
        -                }
        -            else
        -                {
        -                $beforeParameters .= $token;
        -                };
        -            }
        -
        -        else
        -            {
        -            if ($braceLevel > 0)
        -                {  $parameter .= $token;  }
        -            else
        -                {  $beforeParameters .= $token;  };
        -            };
        -        };
        -
        -    foreach my $part (\$beforeParameters, \$afterParameters)
        -        {
        -        $$part =~ s/^ //;
        -        $$part =~ s/ $//;
        -        };
        -
        -    my $prototypeObject = NaturalDocs::Languages::Prototype->New($beforeParameters, $afterParameters);
        -
        -
        -    # Parse the actual parameters.
        -
        -    foreach my $parameterLine (@parameterLines)
        -        {
        -        $prototypeObject->AddParameter( $self->ParseParameterLine($parameterLine) );
        -        };
        -
        -    return $prototypeObject;
        -    };
        -
        -
        -#
        -#   Function: ParseParameterLine
        -#
        -#   Parses a prototype parameter line and returns it as a <NaturalDocs::Languages::Prototype::Parameter> object.
        -#
        -sub ParseParameterLine #(line)
        -    {
        -    my ($self, $line) = @_;
        -    return NaturalDocs::Languages::Prototype::Parameter->New(undef, undef, $line, undef, undef, undef);
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/LineReader.pm b/vendor/naturaldocs/Modules/NaturalDocs/LineReader.pm
        deleted file mode 100644
        index c732afbd2..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/LineReader.pm
        +++ /dev/null
        @@ -1,166 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::LineReader
        -#
        -###############################################################################
        -#
        -#   An object to handle reading text files line by line in a cross platform manner.  Using this class instead of the standard
        -#	angle brackets approach has the following benefits:
        -#
        -#	- It strips all three types of line breaks automatically: CR/LF (Windows) LF (Unix) and CR (Classic Mac).  You do not need to
        -#	  call chomp().  Perl's chomp() fails when parsing Windows-format line breaks on a Unix platform anyway.  It leaves the /r on,
        -#	  which screws everything up.
        -#	- It reads Classic Mac files line by line correctly, whereas the Perl version returns it all as one line.
        -#	- It abstracts away ignoring the Unicode BOM on the first line, if present.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -
        -package NaturalDocs::LineReader;
        -
        -#
        -#	Constants: Members
        -#
        -#	LINEREADER_FILEHANDLE - The file handle being used to read the file.  Has the LINEREADER_ prefix to make sure it doesn't
        -#											 conflict with any actual filehandles named FILEHANDLE in the program.
        -#	CACHED_LINES - An arrayref of lines already read into memory.
        -#
        -use NaturalDocs::DefineMembers 'LINEREADER_FILEHANDLE',
        -                                                 'CACHED_LINES';
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -#   Parameters:
        -#
        -#       filehandle - The file handle being used to read the file.
        -#
        -sub New #(filehandle)
        -    {
        -    my ($selfPackage, $filehandle) = @_;
        -
        -    my $object = [ ];
        -
        -    $object->[LINEREADER_FILEHANDLE] = $filehandle;
        -    $object->[CACHED_LINES] = [ ];
        -
        -    binmode($filehandle, ':raw');
        -
        -    my $possibleBOM = undef;
        -    read($filehandle, $possibleBOM, 2);
        -
        -    if ($possibleBOM eq "\xEF\xBB")
        -        {
        -        read($filehandle, $possibleBOM, 1);
        -        if ($possibleBOM eq "\xBF")
        -            {
        -            seek($filehandle, 3, 0);
        -            binmode($filehandle, ':crlf:encoding(UTF-8)');  # Strict UTF-8, not Perl's lax version.
        -            }
        -        else
        -            {
        -            seek($filehandle, 0, 0);
        -            binmode($filehandle, ':crlf');
        -            }
        -        }
        -    elsif ($possibleBOM eq "\xFE\xFF")
        -        {
        -        seek($filehandle, 2, 0);
        -        binmode($filehandle, ':crlf:encoding(UTF-16BE)');
        -        }
        -    elsif ($possibleBOM eq "\xFF\xFE")
        -        {
        -        seek($filehandle, 2, 0);
        -        binmode($filehandle, ':crlf:encoding(UTF-16LE)');
        -        }
        -    else
        -        {
        -        seek($filehandle, 0, 0);
        -        binmode($filehandle, ':crlf');
        -        }
        -
        -    bless $object, $selfPackage;
        -    return $object;
        -    };
        -
        -
        -#
        -#   Function: Chomp
        -#
        -#   Removes any line breaks from the end of a value.  It does not remove any that are in the middle of it.
        -#
        -#   Parameters:
        -#
        -#       lineRef - A *reference* to the line to chomp.
        -#
        -sub Chomp #(lineRef)
        -    {
        -    my ($self, $lineRef) = @_;
        -    $$lineRef =~ s/(?:\r\n|\r|\n)$//;
        -    };
        -
        -
        -#
        -#	Function: Get
        -#
        -#	Returns the next line of text from the file, or undef if there are no more.  The line break will be removed automatically.  If
        -#	the first line contains a Unicode BOM, that will also be removed automatically.
        -#
        -sub Get
        -	{
        -	my $self = shift;
        -	my $line = undef;
        -
        -	if (scalar @{$self->[CACHED_LINES]} == 0)
        -		{
        -		my $filehandle = $self->[LINEREADER_FILEHANDLE];
        -		my $rawLine = <$filehandle>;
        -
        -		if (!defined $rawLine)
        -			{  return undef;  }
        -
        -		$self->Chomp(\$rawLine);
        -
        -        if ($rawLine =~ /\r/)
        -        	{
        -	  		push @{$self->[CACHED_LINES]}, split(/\r/, $rawLine);  # Split for Classic Mac
        -			$line = shift @{$self->[CACHED_LINES]};
        -          	}
        -        else
        -        	{  $line = $rawLine;  }
        -		}
        -	else
        -		{  $line = shift @{$self->[CACHED_LINES]};  }
        -
        -	return $line;
        -	}
        -
        -
        -#
        -#	Function: GetAll
        -#
        -#	Returns an array of all the lines from the file.  The line breaks will be removed automatically.  If the first line contains a
        -#	Unicode BOM, that will also be removed automatically.
        -#
        -sub GetAll
        -	{
        -	my $self = shift;
        -
        -	my $filehandle = $self->[LINEREADER_FILEHANDLE];
        -	my $rawContent;
        -
        -    read($filehandle, $rawContent, -s $filehandle);
        -
        -    return split(/\r\n|\n|\r/, $rawContent);
        -	}
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Menu.pm b/vendor/naturaldocs/Modules/NaturalDocs/Menu.pm
        deleted file mode 100644
        index f0502d9a0..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Menu.pm
        +++ /dev/null
        @@ -1,3405 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Menu
        -#
        -###############################################################################
        -#
        -#   A package handling the menu's contents and state.
        -#
        -#   Usage and Dependencies:
        -#
        -#       - The <Event Handlers> can be called by <NaturalDocs::Project> immediately.
        -#
        -#       - Prior to initialization, <NaturalDocs::Project> must be initialized, and all files that have been changed must be run
        -#         through <NaturalDocs::Parser->ParseForInformation()>.
        -#
        -#       - To initialize, call <LoadAndUpdate()>.  Afterwards, all other functions are available.  Also, <LoadAndUpdate()> will
        -#         call <NaturalDocs::Settings->GenerateDirectoryNames()>.
        -#
        -#       - To save the changes back to disk, call <Save()>.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use Tie::RefHash;
        -
        -use NaturalDocs::Menu::Entry;
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Menu;
        -
        -
        -#
        -#   Constants: Constants
        -#
        -#   MAXFILESINGROUP - The maximum number of file entries that can be present in a group before it becomes a candidate for
        -#                                  sub-grouping.
        -#   MINFILESINNEWGROUP - The minimum number of file entries that must be present in a group before it will be automatically
        -#                                        created.  This is *not* the number of files that must be in a group before it's deleted.
        -#
        -use constant MAXFILESINGROUP => 6;
        -use constant MINFILESINNEWGROUP => 3;
        -
        -
        -###############################################################################
        -# Group: Variables
        -
        -
        -#
        -#   bool: hasChanged
        -#
        -#   Whether the menu changed or not, regardless of why.
        -#
        -my $hasChanged;
        -
        -
        -#
        -#   Object: menu
        -#
        -#   The parsed menu file.  Is stored as a <MENU_GROUP> <NaturalDocs::Menu::Entry> object, with the top-level entries being
        -#   stored as the group's content.  This is done because it makes a number of functions simpler to implement, plus it allows group
        -#   flags to be set on the top-level.  However, it is exposed externally via <Content()> as an arrayref.
        -#
        -#   This structure will only contain objects for <MENU_FILE>, <MENU_GROUP>, <MENU_TEXT>, <MENU_LINK>, and
        -#   <MENU_INDEX> entries.  Other types, such as <MENU_TITLE>, are stored in variables such as <title>.
        -#
        -my $menu;
        -
        -#
        -#   hash: defaultTitlesChanged
        -#
        -#   An existence hash of default titles that have changed, since <OnDefaultTitleChange()> will be called before
        -#   <LoadAndUpdate()>.  Collects them to be applied later.  The keys are the <FileNames>.
        -#
        -my %defaultTitlesChanged;
        -
        -#
        -#   String: title
        -#
        -#   The title of the menu.
        -#
        -my $title;
        -
        -#
        -#   String: subTitle
        -#
        -#   The sub-title of the menu.
        -#
        -my $subTitle;
        -
        -#
        -#   String: footer
        -#
        -#   The footer for the documentation.
        -#
        -my $footer;
        -
        -#
        -#   String: timestampText
        -#
        -#   The timestamp for the documentation, stored as the final output text.
        -#
        -my $timestampText;
        -
        -#
        -#   String: timestampCode
        -#
        -#   The timestamp for the documentation, storted as the symbolic code.
        -#
        -my $timestampCode;
        -
        -#
        -#   hash: indexes
        -#
        -#   An existence hash of all the defined index <TopicTypes> appearing in the menu.
        -#
        -my %indexes;
        -
        -#
        -#   hash: previousIndexes
        -#
        -#   An existence hash of all the index <TopicTypes> that appeared in the menu last time.
        -#
        -my %previousIndexes;
        -
        -#
        -#   hash: bannedIndexes
        -#
        -#   An existence hash of all the index <TopicTypes> that the user has manually deleted, and thus should not be added back to
        -#   the menu automatically.
        -#
        -my %bannedIndexes;
        -
        -
        -###############################################################################
        -# Group: Files
        -
        -#
        -#   File: Menu.txt
        -#
        -#   The file used to generate the menu.
        -#
        -#   Format:
        -#
        -#       The file is plain text.  Blank lines can appear anywhere and are ignored.  Tags and their content must be completely
        -#       contained on one line with the exception of Group's braces.  All values in brackets below are encoded with entity characters.
        -#
        -#       > # [comment]
        -#
        -#       The file supports single-line comments via #.  They can appear alone on a line or after content.
        -#
        -#       > Format: [version]
        -#       > Title: [title]
        -#       > SubTitle: [subtitle]
        -#       > Footer: [footer]
        -#       > Timestamp: [timestamp code]
        -#
        -#       The file format version, menu title, subtitle, footer, and timestamp are specified as above.  Each can only be specified once,
        -#       with subsequent ones being ignored.  Subtitle is ignored if Title is not present.  Format must be the first entry in the file.  If
        -#       it's not present, it's assumed the menu is from version 0.95 or earlier, since it was added with 1.0.
        -#
        -#       The timestamp code is as follows.
        -#
        -#           m - Single digit month, where applicable.  January is "1".
        -#           mm - Always double digit month.  January is "01".
        -#           mon - Short month word.  January is "Jan".
        -#           month - Long month word.  January is "January".
        -#           d - Single digit day, where applicable.  1 is "1".
        -#           dd - Always double digit day.  1 is "01".
        -#           day - Day with text extension.  1 is "1st".
        -#           yy - Double digit year.  2006 is "06".
        -#           yyyy - Four digit year.  2006 is "2006".
        -#           year - Four digit year.  2006 is "2006".
        -#
        -#       Anything else is left literal in the output.
        -#
        -#       > File: [title] ([file name])
        -#       > File: [title] (auto-title, [file name])
        -#       > File: [title] (no auto-title, [file name])
        -#
        -#       Files are specified as above.  If there is only one input directory, file names are relative.  Otherwise they are absolute.
        -#       If "no auto-title" is specified, the title on the line is used.  If not, the title is ignored and the
        -#       default file title is used instead.  Auto-title defaults to on, so specifying "auto-title" is for compatibility only.
        -#
        -#       > Group: [title]
        -#       > Group: [title] { ... }
        -#
        -#       Groups are specified as above.  If no braces are specified, the group's content is everything that follows until the end of the
        -#       file, the next group (braced or unbraced), or the closing brace of a parent group.  Group braces are the only things in this
        -#       file that can span multiple lines.
        -#
        -#       There is no limitations on where the braces can appear.  The opening brace can appear after the group tag, on its own line,
        -#       or preceding another tag on a line.  Similarly, the closing brace can appear after another tag or on its own line.  Being
        -#       bitchy here would just get in the way of quick and dirty editing; the package will clean it up automatically when it writes it
        -#       back to disk.
        -#
        -#       > Text: [text]
        -#
        -#       Arbitrary text is specified as above.  As with other tags, everything must be contained on the same line.
        -#
        -#       > Link: [URL]
        -#       > Link: [title] ([URL])
        -#
        -#       External links can be specified as above.  If the titled form is not used, the URL is used as the title.
        -#
        -#       > Index: [name]
        -#       > [topic type name] Index: [name]
        -#
        -#       Indexes are specified as above.  The topic type names can be either singular or plural.  General is assumed if not specified.
        -#
        -#       > Don't Index: [topic type name]
        -#       > Don't Index: [topic type name], [topic type name], ...
        -#
        -#       The option above prevents indexes that exist but are not on the menu from being automatically added.
        -#
        -#       > Data: [number]([obscured data])
        -#
        -#       Used to store non-user editable data.
        -#
        -#       > Data: 1([obscured: [directory name]///[input directory]])
        -#
        -#       When there is more than one directory, these lines store the input directories used in the last run and their names.  This
        -#       allows menu files to be shared across machines since the names will be consistent and the directories can be used to convert
        -#       filenames to the local machine's paths.  We don't want this user-editable because they may think changing it changes the
        -#       input directories, when it doesn't.  Also, changing it without changing all the paths screws up resolving.
        -#
        -#       > Data: 2([obscured: [directory name])
        -#
        -#       When there is only one directory and its name is not "default", this stores the name.
        -#
        -#
        -#   Entities:
        -#
        -#       &amp; - Ampersand.
        -#       &lparen; - Left parenthesis.
        -#       &rparen; - Right parenthesis.
        -#       &lbrace; - Left brace.
        -#       &rbrace; - Right brace.
        -#
        -#
        -#   Revisions:
        -#
        -#       1.4:
        -#
        -#           - Added Timestamp property.
        -#           - Values are now encoded with entity characters.
        -#
        -#       1.3:
        -#
        -#           - File names are now relative again if there is only one input directory.
        -#           - Data: 2(...) added.
        -#           - Can't use synonyms like "copyright" for "footer" or "sub-title" for "subtitle".
        -#           - "Don't Index" line now requires commas to separate them, whereas it tolerated just spaces before.
        -#
        -#       1.16:
        -#
        -#           - File names are now absolute instead of relative.  Prior to 1.16 only one input directory was allowed, so they could be
        -#             relative.
        -#           - Data keywords introduced to store input directories and their names.
        -#
        -#       1.14:
        -#
        -#           - Renamed this file from NaturalDocs_Menu.txt to Menu.txt.
        -#
        -#       1.1:
        -#
        -#           - Added the "don't index" line.
        -#
        -#           This is also the point where indexes were automatically added and removed, so all index entries from prior revisions
        -#           were manually added and are not guaranteed to contain anything.
        -#
        -#       1.0:
        -#
        -#           - Added the format line.
        -#           - Added the "no auto-title" attribute.
        -#           - Changed the file entry default to auto-title.
        -#
        -#           This is also the point where auto-organization and better auto-titles were introduced.  All groups in prior revisions were
        -#           manually added, with the exception of a top-level Other group where new files were automatically added if there were
        -#           groups defined.
        -#
        -#       Break in support:
        -#
        -#           Releases prior to 1.0 are no longer supported.  Why?
        -#
        -#           - They don't have a Format: line, which is required by <NaturalDocs::ConfigFile>, although I could work around this
        -#             if I needed to.
        -#           - No significant number of downloads for pre-1.0 releases.
        -#           - Code simplification.  I don't have to bridge the conversion from manual-only menu organization to automatic.
        -#
        -#       0.9:
        -#
        -#           - Added index entries.
        -#
        -
        -#
        -#   File: PreviousMenuState.nd
        -#
        -#   The file used to store the previous state of the menu so as to detect changes.
        -#
        -#
        -#   Format:
        -#
        -#   > [BINARY_FORMAT]
        -#   > [VersionInt: app version]
        -#
        -#   First is the standard <BINARY_FORMAT> <VersionInt> header.
        -#
        -#   > [UInt8: 0 (end group)]
        -#   > [UInt8: MENU_FILE] [UInt8: noAutoTitle] [AString16: title] [AString16: target]
        -#   > [UInt8: MENU_GROUP] [AString16: title]
        -#   > [UInt8: MENU_INDEX] [AString16: title] [AString16: topic type]
        -#   > [UInt8: MENU_LINK] [AString16: title] [AString16: url]
        -#   > [UInt8: MENU_TEXT] [AString16: text]
        -#
        -#   The first UInt8 of each following line is either zero or one of the <Menu Entry Types>.  What follows is contextual.
        -#
        -#   There are no entries for title, subtitle, or footer.  Only the entries present in <menu>.
        -#
        -#   See Also:
        -#
        -#       <File Format Conventions>
        -#
        -#   Dependencies:
        -#
        -#       - Because the type is represented by a UInt8, the <Menu Entry Types> must all be <= 255.
        -#
        -#   Revisions:
        -#
        -#       1.3:
        -#
        -#           - The topic type following the <MENU_INDEX> entries were changed from UInt8s to AString16s, since <TopicTypes>
        -#             were switched from integer constants to strings.  You can still convert the old to the new via
        -#             <NaturalDocs::Topics->TypeFromLegacy()>.
        -#
        -#       1.16:
        -#
        -#           - The file targets are now absolute.  Prior to 1.16, they were relative to the input directory since only one was allowed.
        -#
        -#       1.14:
        -#
        -#           - The file was renamed from NaturalDocs.m to PreviousMenuState.nd and moved into the Data subdirectory.
        -#
        -#       1.0:
        -#
        -#           - The file's format was completely redone.  Prior to 1.0, the file was a text file consisting of the app version and a line
        -#             which was a tab-separated list of the indexes present in the menu.  * meant the general index.
        -#
        -#       Break in support:
        -#
        -#           Pre-1.0 files are no longer supported.  There was no significant number of downloads for pre-1.0 releases, and this
        -#           eliminates a separate code path for them.
        -#
        -#       0.95:
        -#
        -#           - Change the file version to match the app version.  Prior to 0.95, the version line was 1.  Test for "1" instead of "1.0" to
        -#             distinguish.
        -#
        -#       0.9:
        -#
        -#           - The file was added to the project.  Prior to 0.9, it didn't exist.
        -#
        -
        -
        -###############################################################################
        -# Group: File Functions
        -
        -#
        -#   Function: LoadAndUpdate
        -#
        -#   Loads the menu file from disk and updates it.  Will add, remove, rearrange, and remove auto-titling from entries as
        -#   necessary.  Will also call <NaturalDocs::Settings->GenerateDirectoryNames()>.
        -#
        -sub LoadAndUpdate
        -    {
        -    my ($self) = @_;
        -
        -    my ($inputDirectoryNames, $relativeFiles, $onlyDirectoryName) = $self->LoadMenuFile();
        -
        -    my $errorCount = NaturalDocs::ConfigFile->ErrorCount();
        -    if ($errorCount)
        -        {
        -        NaturalDocs::ConfigFile->PrintErrorsAndAnnotateFile();
        -        NaturalDocs::Error->SoftDeath('There ' . ($errorCount == 1 ? 'is an error' : 'are ' . $errorCount . ' errors')
        -                                                    . ' in ' . NaturalDocs::Project->UserConfigFile('Menu.txt'));
        -        };
        -
        -    # If the menu has a timestamp and today is a different day than the last time Natural Docs was run, we have to count it as the
        -    # menu changing.
        -    if (defined $timestampCode)
        -        {
        -        my (undef, undef, undef, $currentDay, $currentMonth, $currentYear) = localtime();
        -        my (undef, undef, undef, $lastDay, $lastMonth, $lastYear) =
        -            localtime( (stat( NaturalDocs::Project->DataFile('PreviousMenuState.nd') ))[9] );
        -            # This should be okay if the previous menu state file doesn't exist.
        -
        -        if ($currentDay != $lastDay || $currentMonth != $lastMonth || $currentYear != $lastYear)
        -            {  $hasChanged = 1;  };
        -        };
        -
        -
        -    if ($relativeFiles)
        -        {
        -        my $inputDirectory = $self->ResolveRelativeInputDirectories($onlyDirectoryName);
        -
        -        if ($onlyDirectoryName)
        -            {  $inputDirectoryNames = { $inputDirectory => $onlyDirectoryName };  };
        -        }
        -    else
        -        {  $self->ResolveInputDirectories($inputDirectoryNames);  };
        -
        -    NaturalDocs::Settings->GenerateDirectoryNames($inputDirectoryNames);
        -
        -    my $filesInMenu = $self->FilesInMenu();
        -
        -    my ($previousMenu, $previousIndexes, $previousFiles) = $self->LoadPreviousMenuStateFile();
        -
        -    if (defined $previousIndexes)
        -        {  %previousIndexes = %$previousIndexes;  };
        -
        -    if (defined $previousFiles)
        -        {  $self->LockUserTitleChanges($previousFiles);  };
        -
        -    # Don't need these anymore.  We keep this level of detail because it may be used more in the future.
        -    $previousMenu = undef;
        -    $previousFiles = undef;
        -    $previousIndexes = undef;
        -
        -    # We flag title changes instead of actually performing them at this point for two reasons.  First, contents of groups are still
        -    # subject to change, which would affect the generated titles.  Second, we haven't detected the sort order yet.  Changing titles
        -    # could make groups appear unalphabetized when they were beforehand.
        -
        -    my $updateAllTitles;
        -
        -    # If the menu file changed, we can't be sure which groups changed and which didn't without a comparison, which really isn't
        -    # worth the trouble.  So we regenerate all the titles instead.
        -    if (NaturalDocs::Project->UserConfigFileStatus('Menu.txt') == ::FILE_CHANGED())
        -        {  $updateAllTitles = 1;  }
        -    else
        -        {  $self->FlagAutoTitleChanges();  };
        -
        -    # We add new files before deleting old files so their presence still affects the grouping.  If we deleted old files first, it could
        -    # throw off where to place the new ones.
        -
        -    $self->AutoPlaceNewFiles($filesInMenu);
        -
        -    my $numberRemoved = $self->RemoveDeadFiles();
        -
        -    $self->CheckForTrashedMenu(scalar keys %$filesInMenu, $numberRemoved);
        -
        -    # Don't ban indexes if they deleted Menu.txt.  They may have not deleted PreviousMenuState.nd and we don't want everything
        -    # to be banned because of it.
        -    if (NaturalDocs::Project->UserConfigFileStatus('Menu.txt') != ::FILE_DOESNTEXIST())
        -        {  $self->BanAndUnbanIndexes();  };
        -
        -    # Index groups need to be detected before adding new ones.
        -
        -    $self->DetectIndexGroups();
        -
        -    $self->AddAndRemoveIndexes();
        -
        -   # We wait until after new files are placed to remove dead groups because a new file may save a group.
        -
        -    $self->RemoveDeadGroups();
        -
        -    $self->CreateDirectorySubGroups();
        -
        -    # We detect the sort before regenerating the titles so it doesn't get thrown off by changes.  However, we do it after deleting
        -    # dead entries and moving things into subgroups because their removal may bump it into a stronger sort category (i.e.
        -    # SORTFILESANDGROUPS instead of just SORTFILES.)  New additions don't factor into the sort.
        -
        -    $self->DetectOrder($updateAllTitles);
        -
        -    $self->GenerateAutoFileTitles($updateAllTitles);
        -
        -    $self->ResortGroups($updateAllTitles);
        -
        -
        -    # Don't need this anymore.
        -    %defaultTitlesChanged = ( );
        -    };
        -
        -
        -#
        -#   Function: Save
        -#
        -#   Writes the changes to the menu files.
        -#
        -sub Save
        -    {
        -    my ($self) = @_;
        -
        -    if ($hasChanged)
        -        {
        -        $self->SaveMenuFile();
        -        $self->SavePreviousMenuStateFile();
        -        };
        -    };
        -
        -
        -###############################################################################
        -# Group: Information Functions
        -
        -#
        -#   Function: HasChanged
        -#
        -#   Returns whether the menu has changed or not.
        -#
        -sub HasChanged
        -    {  return $hasChanged;  };
        -
        -#
        -#   Function: Content
        -#
        -#   Returns the parsed menu as an arrayref of <NaturalDocs::Menu::Entry> objects.  Do not change the arrayref.
        -#
        -#   The arrayref will only contain <MENU_FILE>, <MENU_GROUP>, <MENU_INDEX>, <MENU_TEXT>, and <MENU_LINK>
        -#   entries.  Entries such as <MENU_TITLE> are parsed out and are only accessible via functions such as <Title()>.
        -#
        -sub Content
        -    {  return $menu->GroupContent();  };
        -
        -#
        -#   Function: Title
        -#
        -#   Returns the title of the menu, or undef if none.
        -#
        -sub Title
        -    {  return $title;  };
        -
        -#
        -#   Function: SubTitle
        -#
        -#   Returns the sub-title of the menu, or undef if none.
        -#
        -sub SubTitle
        -    {  return $subTitle;  };
        -
        -#
        -#   Function: Footer
        -#
        -#   Returns the footer of the documentation, or undef if none.
        -#
        -sub Footer
        -    {  return $footer;  };
        -
        -#
        -#   Function: TimeStamp
        -#
        -#   Returns the timestamp text of the documentation, or undef if none.
        -#
        -sub TimeStamp
        -    {  return $timestampText;  };
        -
        -#
        -#   Function: Indexes
        -#
        -#   Returns an existence hashref of all the index <TopicTypes> appearing in the menu.  Do not change the hashref.
        -#
        -sub Indexes
        -    {  return \%indexes;  };
        -
        -#
        -#   Function: PreviousIndexes
        -#
        -#   Returns an existence hashref of all the index <TopicTypes> that previously appeared in the menu.  Do not change the
        -#   hashref.
        -#
        -sub PreviousIndexes
        -    {  return \%previousIndexes;  };
        -
        -
        -#
        -#   Function: FilesInMenu
        -#
        -#   Returns a hashref of all the files present in the menu.  The keys are the <FileNames>, and the values are references to their
        -#   <NaturalDocs::Menu::Entry> objects.
        -#
        -sub FilesInMenu
        -    {
        -    my ($self) = @_;
        -
        -    my @groupStack = ( $menu );
        -    my $filesInMenu = { };
        -
        -    while (scalar @groupStack)
        -        {
        -        my $currentGroup = pop @groupStack;
        -        my $currentGroupContent = $currentGroup->GroupContent();
        -
        -        foreach my $entry (@$currentGroupContent)
        -            {
        -            if ($entry->Type() == ::MENU_GROUP())
        -                {  push @groupStack, $entry;  }
        -            elsif ($entry->Type() == ::MENU_FILE())
        -                {  $filesInMenu->{ $entry->Target() } = $entry;  };
        -            };
        -        };
        -
        -    return $filesInMenu;
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Event Handlers
        -#
        -#   These functions are called by <NaturalDocs::Project> only.  You don't need to worry about calling them.  For example, when
        -#   changing the default menu title of a file, you only need to call <NaturalDocs::Project->SetDefaultMenuTitle()>.  That function
        -#   will handle calling <OnDefaultTitleChange()>.
        -
        -
        -#
        -#   Function: OnDefaultTitleChange
        -#
        -#   Called by <NaturalDocs::Project> if the default menu title of a source file has changed.
        -#
        -#   Parameters:
        -#
        -#       file    - The source <FileName> that had its default menu title changed.
        -#
        -sub OnDefaultTitleChange #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    # Collect them for later.  We'll deal with them in LoadAndUpdate().
        -
        -    $defaultTitlesChanged{$file} = 1;
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -
        -#
        -#   Function: LoadMenuFile
        -#
        -#   Loads and parses the menu file <Menu.txt>.  This will fill <menu>, <title>, <subTitle>, <footer>, <timestampText>,
        -#   <timestampCode>, <indexes>, and <bannedIndexes>.  If there are any errors in the file, they will be recorded with
        -#   <NaturalDocs::ConfigFile->AddError()>.
        -#
        -#   Returns:
        -#
        -#       The array ( inputDirectories, relativeFiles, onlyDirectoryName ) or an empty array if the file doesn't exist.
        -#
        -#       inputDirectories - A hashref of all the input directories and their names stored in the menu file.  The keys are the
        -#                                 directories and the values are their names.  Undef if none.
        -#       relativeFiles - Whether the menu uses relative file names.
        -#       onlyDirectoryName - The name of the input directory if there is only one.
        -#
        -sub LoadMenuFile
        -    {
        -    my ($self) = @_;
        -
        -    my $inputDirectories = { };
        -    my $relativeFiles;
        -    my $onlyDirectoryName;
        -
        -    # A stack of Menu::Entry object references as we move through the groups.
        -    my @groupStack;
        -
        -    $menu = NaturalDocs::Menu::Entry->New(::MENU_GROUP(), undef, undef, undef);
        -    my $currentGroup = $menu;
        -
        -    # Whether we're currently in a braceless group, since we'd have to find the implied end rather than an explicit one.
        -    my $inBracelessGroup;
        -
        -    # Whether we're right after a group token, which is the only place there can be an opening brace.
        -    my $afterGroupToken;
        -
        -    my $version;
        -
        -    if ($version = NaturalDocs::ConfigFile->Open(NaturalDocs::Project->UserConfigFile('Menu.txt'), 1))
        -        {
        -        # We don't check if the menu file is from a future version because we can't just throw it out and regenerate it like we can
        -        # with other data files.  So we just keep going regardless.  Any syntactic differences will show up as errors.
        -
        -        while (my ($keyword, $value, $comment) = NaturalDocs::ConfigFile->GetLine())
        -            {
        -            # Check for an opening brace after a group token.  This has to be separate from the rest of the code because the flag
        -            # needs to be reset after every line.
        -            if ($afterGroupToken)
        -                {
        -                $afterGroupToken = undef;
        -
        -                if ($keyword eq '{')
        -                    {
        -                    $inBracelessGroup = undef;
        -                    next;
        -                    }
        -                else
        -                    {  $inBracelessGroup = 1;  };
        -                };
        -
        -
        -            # Now on to the real code.
        -
        -            if ($keyword eq 'file')
        -                {
        -                my $flags = 0;
        -
        -                if ($value =~ /^(.+)\(([^\(]+)\)$/)
        -                    {
        -                    my ($title, $file) = ($1, $2);
        -
        -                    $title =~ s/ +$//;
        -
        -                    # Check for auto-title modifier.
        -                    if ($file =~ /^((?:no )?auto-title, ?)(.+)$/i)
        -                        {
        -                        my $modifier;
        -                        ($modifier, $file) = ($1, $2);
        -
        -                        if ($modifier =~ /^no/i)
        -                            {  $flags |= ::MENU_FILE_NOAUTOTITLE();  };
        -                        };
        -
        -                    my $entry = NaturalDocs::Menu::Entry->New(::MENU_FILE(), $self->RestoreAmpChars($title),
        -                                                                                       $self->RestoreAmpChars($file), $flags);
        -
        -                    $currentGroup->PushToGroup($entry);
        -                    }
        -                else
        -                    {  NaturalDocs::ConfigFile->AddError('File lines must be in the format "File: [title] ([location])"');  };
        -                }
        -
        -            elsif ($keyword eq 'group')
        -                {
        -                # End a braceless group, if we were in one.
        -                if ($inBracelessGroup)
        -                    {
        -                    $currentGroup = pop @groupStack;
        -                    $inBracelessGroup = undef;
        -                    };
        -
        -                my $entry = NaturalDocs::Menu::Entry->New(::MENU_GROUP(), $self->RestoreAmpChars($value), undef, undef);
        -
        -                $currentGroup->PushToGroup($entry);
        -
        -                push @groupStack, $currentGroup;
        -                $currentGroup = $entry;
        -
        -                $afterGroupToken = 1;
        -                }
        -
        -
        -            elsif ($keyword eq '{')
        -                {
        -                NaturalDocs::ConfigFile->AddError('Opening braces are only allowed after Group tags.');
        -                }
        -
        -
        -            elsif ($keyword eq '}')
        -                {
        -                # End a braceless group, if we were in one.
        -                if ($inBracelessGroup)
        -                    {
        -                    $currentGroup = pop @groupStack;
        -                    $inBracelessGroup = undef;
        -                    };
        -
        -                # End a braced group too.
        -                if (scalar @groupStack)
        -                    {  $currentGroup = pop @groupStack;  }
        -                else
        -                    {  NaturalDocs::ConfigFile->AddError('Unmatched closing brace.');  };
        -                }
        -
        -
        -            elsif ($keyword eq 'title')
        -                {
        -                if (!defined $title)
        -                    {  $title = $self->RestoreAmpChars($value);  }
        -                else
        -                    {  NaturalDocs::ConfigFile->AddError('Title can only be defined once.');  };
        -                }
        -
        -
        -            elsif ($keyword eq 'subtitle')
        -                {
        -                if (defined $title)
        -                    {
        -                    if (!defined $subTitle)
        -                        {  $subTitle = $self->RestoreAmpChars($value);  }
        -                    else
        -                        {  NaturalDocs::ConfigFile->AddError('SubTitle can only be defined once.');  };
        -                    }
        -                else
        -                    {  NaturalDocs::ConfigFile->AddError('Title must be defined before SubTitle.');  };
        -                }
        -
        -
        -            elsif ($keyword eq 'footer')
        -                {
        -                if (!defined $footer)
        -                    {  $footer = $self->RestoreAmpChars($value);  }
        -                else
        -                    {  NaturalDocs::ConfigFile->AddError('Footer can only be defined once.');  };
        -                }
        -
        -
        -            elsif ($keyword eq 'timestamp')
        -                {
        -                if (!defined $timestampCode)
        -                    {
        -                    $timestampCode = $self->RestoreAmpChars($value);
        -                    $self->GenerateTimestampText();
        -                    }
        -                else
        -                    {  NaturalDocs::ConfigFile->AddError('Timestamp can only be defined once.');  };
        -                }
        -
        -
        -            elsif ($keyword eq 'text')
        -                {
        -                $currentGroup->PushToGroup( NaturalDocs::Menu::Entry->New(::MENU_TEXT(), $self->RestoreAmpChars($value),
        -                                                                                                              undef, undef) );
        -                }
        -
        -
        -            elsif ($keyword eq 'link')
        -                {
        -                my ($title, $url);
        -
        -                if ($value =~ /^([^\(\)]+?) ?\(([^\)]+)\)$/)
        -                    {
        -                    ($title, $url) = ($1, $2);
        -                    }
        -                elsif (defined $comment)
        -                    {
        -                    $value .= $comment;
        -
        -                    if ($value =~ /^([^\(\)]+?) ?\(([^\)]+)\) ?(?:#.*)?$/)
        -                        {
        -                        ($title, $url) = ($1, $2);
        -                        };
        -                    };
        -
        -                if ($title)
        -                    {
        -                    $currentGroup->PushToGroup( NaturalDocs::Menu::Entry->New(::MENU_LINK(), $self->RestoreAmpChars($title),
        -                                                                 $self->RestoreAmpChars($url), undef) );
        -                    }
        -                else
        -                    {  NaturalDocs::ConfigFile->AddError('Link lines must be in the format "Link: [title] ([url])"');  };
        -                }
        -
        -
        -            elsif ($keyword eq 'data')
        -                {
        -                $value =~ /^(\d)\((.*)\)$/;
        -                my ($number, $data) = ($1, $2);
        -
        -                $data = NaturalDocs::ConfigFile->Unobscure($data);
        -
        -                # The input directory naming convention changed with version 1.32, but NaturalDocs::Settings will handle that
        -                # automatically.
        -
        -                if ($number == 1)
        -                    {
        -                    my ($dirName, $inputDir) = split(/\/\/\//, $data, 2);
        -                    $inputDirectories->{$inputDir} = $dirName;
        -                    }
        -                elsif ($number == 2)
        -                    {  $onlyDirectoryName = $data;  };
        -                # Ignore other numbers because it may be from a future format and we don't want to make the user delete it
        -                # manually.
        -                }
        -
        -            elsif ($keyword eq "don't index")
        -                {
        -                my @indexes = split(/, ?/, $value);
        -
        -                foreach my $index (@indexes)
        -                    {
        -                    my $indexType = NaturalDocs::Topics->TypeFromName( $self->RestoreAmpChars($index) );
        -
        -                    if (defined $indexType)
        -                        {  $bannedIndexes{$indexType} = 1;  };
        -                    };
        -                }
        -
        -            elsif ($keyword eq 'index')
        -                {
        -                my $entry = NaturalDocs::Menu::Entry->New(::MENU_INDEX(), $self->RestoreAmpChars($value),
        -                                                                                   ::TOPIC_GENERAL(), undef);
        -                $currentGroup->PushToGroup($entry);
        -
        -                $indexes{::TOPIC_GENERAL()} = 1;
        -                }
        -
        -            elsif (substr($keyword, -6) eq ' index')
        -                {
        -                my $index = substr($keyword, 0, -6);
        -                my ($indexType, $indexInfo) = NaturalDocs::Topics->NameInfo( $self->RestoreAmpChars($index) );
        -
        -                if (defined $indexType)
        -                    {
        -                    if ($indexInfo->Index())
        -                        {
        -                        $indexes{$indexType} = 1;
        -                        $currentGroup->PushToGroup(
        -                            NaturalDocs::Menu::Entry->New(::MENU_INDEX(), $self->RestoreAmpChars($value), $indexType, undef) );
        -                        }
        -                    else
        -                        {
        -                        # If it's on the menu but isn't indexable, the topic setting may have changed out from under it.
        -                        $hasChanged = 1;
        -                        };
        -                    }
        -                else
        -                    {
        -                    NaturalDocs::ConfigFile->AddError($index . ' is not a valid index type.');
        -                    };
        -                }
        -
        -            else
        -                {
        -                NaturalDocs::ConfigFile->AddError(ucfirst($keyword) . ' is not a valid keyword.');
        -                };
        -            };
        -
        -
        -        # End a braceless group, if we were in one.
        -        if ($inBracelessGroup)
        -            {
        -            $currentGroup = pop @groupStack;
        -            $inBracelessGroup = undef;
        -            };
        -
        -        # Close up all open groups.
        -        my $openGroups = 0;
        -        while (scalar @groupStack)
        -            {
        -            $currentGroup = pop @groupStack;
        -            $openGroups++;
        -            };
        -
        -        if ($openGroups == 1)
        -            {  NaturalDocs::ConfigFile->AddError('There is an unclosed group.');  }
        -        elsif ($openGroups > 1)
        -            {  NaturalDocs::ConfigFile->AddError('There are ' . $openGroups . ' unclosed groups.');  };
        -
        -
        -        if (!scalar keys %$inputDirectories)
        -            {
        -            $inputDirectories = undef;
        -            $relativeFiles = 1;
        -            };
        -
        -        NaturalDocs::ConfigFile->Close();
        -
        -        return ($inputDirectories, $relativeFiles, $onlyDirectoryName);
        -        }
        -
        -    else
        -        {  return ( );  };
        -    };
        -
        -
        -#
        -#   Function: SaveMenuFile
        -#
        -#   Saves the current menu to <Menu.txt>.
        -#
        -sub SaveMenuFile
        -    {
        -    my ($self) = @_;
        -
        -    open(MENUFILEHANDLE, '>' . NaturalDocs::Project->UserConfigFile('Menu.txt'))
        -        or die "Couldn't save menu file " . NaturalDocs::Project->UserConfigFile('Menu.txt') . "\n";
        -
        -
        -    print MENUFILEHANDLE
        -    "Format: " . NaturalDocs::Settings->TextAppVersion() . "\n\n\n";
        -
        -    my $inputDirs = NaturalDocs::Settings->InputDirectories();
        -
        -
        -    if (defined $title)
        -        {
        -        print MENUFILEHANDLE 'Title: ' . $self->ConvertAmpChars($title) . "\n";
        -
        -        if (defined $subTitle)
        -            {
        -            print MENUFILEHANDLE 'SubTitle: ' . $self->ConvertAmpChars($subTitle) . "\n";
        -            }
        -        else
        -            {
        -            print MENUFILEHANDLE
        -            "\n"
        -            . "# You can also add a sub-title to your menu like this:\n"
        -            . "# SubTitle: [subtitle]\n";
        -            };
        -        }
        -    else
        -        {
        -        print MENUFILEHANDLE
        -        "# You can add a title and sub-title to your menu like this:\n"
        -        . "# Title: [project name]\n"
        -        . "# SubTitle: [subtitle]\n";
        -        };
        -
        -    print MENUFILEHANDLE "\n";
        -
        -    if (defined $footer)
        -        {
        -        print MENUFILEHANDLE 'Footer: ' . $self->ConvertAmpChars($footer) . "\n";
        -        }
        -    else
        -        {
        -        print MENUFILEHANDLE
        -        "# You can add a footer to your documentation like this:\n"
        -        . "# Footer: [text]\n"
        -        . "# If you want to add a copyright notice, this would be the place to do it.\n";
        -        };
        -
        -    if (defined $timestampCode)
        -        {
        -        print MENUFILEHANDLE 'Timestamp: ' . $self->ConvertAmpChars($timestampCode) . "\n";
        -        }
        -    else
        -        {
        -        print MENUFILEHANDLE
        -        "\n"
        -        . "# You can add a timestamp to your documentation like one of these:\n"
        -        . "# Timestamp: Generated on month day, year\n"
        -        . "# Timestamp: Updated mm/dd/yyyy\n"
        -        . "# Timestamp: Last updated mon day\n"
        -        . "#\n";
        -        };
        -
        -    print MENUFILEHANDLE
        -        qq{#   m     - One or two digit month.  January is "1"\n}
        -        . qq{#   mm    - Always two digit month.  January is "01"\n}
        -        . qq{#   mon   - Short month word.  January is "Jan"\n}
        -        . qq{#   month - Long month word.  January is "January"\n}
        -        . qq{#   d     - One or two digit day.  1 is "1"\n}
        -        . qq{#   dd    - Always two digit day.  1 is "01"\n}
        -        . qq{#   day   - Day with letter extension.  1 is "1st"\n}
        -        . qq{#   yy    - Two digit year.  2006 is "06"\n}
        -        . qq{#   yyyy  - Four digit year.  2006 is "2006"\n}
        -        . qq{#   year  - Four digit year.  2006 is "2006"\n}
        -
        -        . "\n";
        -
        -    if (scalar keys %bannedIndexes)
        -        {
        -        print MENUFILEHANDLE
        -
        -        "# These are indexes you deleted, so Natural Docs will not add them again\n"
        -        . "# unless you remove them from this line.\n"
        -        . "\n"
        -        . "Don't Index: ";
        -
        -        my $first = 1;
        -
        -        foreach my $index (keys %bannedIndexes)
        -            {
        -            if (!$first)
        -                {  print MENUFILEHANDLE ', ';  }
        -            else
        -                {  $first = undef;  };
        -
        -            print MENUFILEHANDLE $self->ConvertAmpChars( NaturalDocs::Topics->NameOfType($index, 1), CONVERT_COMMAS() );
        -            };
        -
        -        print MENUFILEHANDLE "\n\n";
        -        };
        -
        -
        -    # Remember to keep lines below eighty characters.
        -
        -    print MENUFILEHANDLE
        -    "\n"
        -    . "# --------------------------------------------------------------------------\n"
        -    . "# \n"
        -    . "# Cut and paste the lines below to change the order in which your files\n"
        -    . "# appear on the menu.  Don't worry about adding or removing files, Natural\n"
        -    . "# Docs will take care of that.\n"
        -    . "# \n"
        -    . "# You can further organize the menu by grouping the entries.  Add a\n"
        -    . "# \"Group: [name] {\" line to start a group, and add a \"}\" to end it.\n"
        -    . "# \n"
        -    . "# You can add text and web links to the menu by adding \"Text: [text]\" and\n"
        -    . "# \"Link: [name] ([URL])\" lines, respectively.\n"
        -    . "# \n"
        -    . "# The formatting and comments are auto-generated, so don't worry about\n"
        -    . "# neatness when editing the file.  Natural Docs will clean it up the next\n"
        -    . "# time it is run.  When working with groups, just deal with the braces and\n"
        -    . "# forget about the indentation and comments.\n"
        -    . "# \n";
        -
        -    if (scalar @$inputDirs > 1)
        -        {
        -        print MENUFILEHANDLE
        -        "# You can use this file on other computers even if they use different\n"
        -        . "# directories.  As long as the command line points to the same source files,\n"
        -        . "# Natural Docs will be able to correct the locations automatically.\n"
        -        . "# \n";
        -        };
        -
        -    print MENUFILEHANDLE
        -    "# --------------------------------------------------------------------------\n"
        -
        -    . "\n\n";
        -
        -
        -    $self->WriteMenuEntries($menu->GroupContent(), \*MENUFILEHANDLE, undef, (scalar @$inputDirs == 1));
        -
        -
        -    if (scalar @$inputDirs > 1)
        -        {
        -        print MENUFILEHANDLE
        -        "\n\n##### Do not change or remove these lines. #####\n";
        -
        -        foreach my $inputDir (@$inputDirs)
        -            {
        -            print MENUFILEHANDLE
        -            'Data: 1(' . NaturalDocs::ConfigFile->Obscure( NaturalDocs::Settings->InputDirectoryNameOf($inputDir)
        -                                                                              . '///' . $inputDir ) . ")\n";
        -            };
        -        }
        -    elsif (lc(NaturalDocs::Settings->InputDirectoryNameOf($inputDirs->[0])) != 1)
        -        {
        -        print MENUFILEHANDLE
        -        "\n\n##### Do not change or remove this line. #####\n"
        -        . 'Data: 2(' . NaturalDocs::ConfigFile->Obscure( NaturalDocs::Settings->InputDirectoryNameOf($inputDirs->[0]) ) . ")\n";
        -        }
        -
        -    close(MENUFILEHANDLE);
        -    };
        -
        -
        -#
        -#   Function: WriteMenuEntries
        -#
        -#   A recursive function to write the contents of an arrayref of <NaturalDocs::Menu::Entry> objects to disk.
        -#
        -#   Parameters:
        -#
        -#       entries          - The arrayref of menu entries to write.
        -#       fileHandle      - The handle to the output file.
        -#       indentChars   - The indentation _characters_ to add before each line.  It is not the number of characters, it is the characters
        -#                              themselves.  Use undef for none.
        -#       relativeFiles - Whether to use relative file names.
        -#
        -sub WriteMenuEntries #(entries, fileHandle, indentChars, relativeFiles)
        -    {
        -    my ($self, $entries, $fileHandle, $indentChars, $relativeFiles) = @_;
        -    my $lastEntryType;
        -
        -    foreach my $entry (@$entries)
        -        {
        -        if ($entry->Type() == ::MENU_FILE())
        -            {
        -            my $fileName;
        -
        -            if ($relativeFiles)
        -                {  $fileName = (NaturalDocs::Settings->SplitFromInputDirectory($entry->Target()))[1];  }
        -            else
        -                {  $fileName = $entry->Target();  };
        -
        -            print $fileHandle $indentChars . 'File: ' . $self->ConvertAmpChars( $entry->Title(), CONVERT_PARENTHESIS() )
        -                                  . '  (' . ($entry->Flags() & ::MENU_FILE_NOAUTOTITLE() ? 'no auto-title, ' : '')
        -                                  . $self->ConvertAmpChars($fileName) . ")\n";
        -            }
        -        elsif ($entry->Type() == ::MENU_GROUP())
        -            {
        -            if (defined $lastEntryType && $lastEntryType != ::MENU_GROUP())
        -                {  print $fileHandle "\n";  };
        -
        -            print $fileHandle $indentChars . 'Group: ' . $self->ConvertAmpChars( $entry->Title() ) . "  {\n\n";
        -            $self->WriteMenuEntries($entry->GroupContent(), $fileHandle, '   ' . $indentChars, $relativeFiles);
        -            print $fileHandle '   ' . $indentChars . '}  # Group: ' . $self->ConvertAmpChars( $entry->Title() ) . "\n\n";
        -            }
        -        elsif ($entry->Type() == ::MENU_TEXT())
        -            {
        -            print $fileHandle $indentChars . 'Text: ' . $self->ConvertAmpChars( $entry->Title() ) . "\n";
        -            }
        -        elsif ($entry->Type() == ::MENU_LINK())
        -            {
        -            print $fileHandle $indentChars . 'Link: ' . $self->ConvertAmpChars( $entry->Title() ) . '  '
        -                                                        . '(' . $self->ConvertAmpChars( $entry->Target(), CONVERT_PARENTHESIS() ) . ')' . "\n";
        -            }
        -        elsif ($entry->Type() == ::MENU_INDEX())
        -            {
        -            my $type;
        -            if ($entry->Target() ne ::TOPIC_GENERAL())
        -                {
        -                $type = NaturalDocs::Topics->NameOfType($entry->Target()) . ' ';
        -                };
        -
        -            print $fileHandle $indentChars . $self->ConvertAmpChars($type, CONVERT_COLONS()) . 'Index: '
        -                                                        . $self->ConvertAmpChars( $entry->Title() ) . "\n";
        -            };
        -
        -        $lastEntryType = $entry->Type();
        -        };
        -    };
        -
        -
        -#
        -#   Function: LoadPreviousMenuStateFile
        -#
        -#   Loads and parses the previous menu state file.
        -#
        -#   Returns:
        -#
        -#       The array ( previousMenu, previousIndexes, previousFiles ) or an empty array if there was a problem with the file.
        -#
        -#       previousMenu - A <MENU_GROUP> <NaturalDocs::Menu::Entry> object, similar to <menu>, which contains the entire
        -#                              previous menu.
        -#       previousIndexes - An existence hashref of the index <TopicTypes> present in the previous menu.
        -#       previousFiles - A hashref of the files present in the previous menu.  The keys are the <FileNames>, and the entries are
        -#                             references to its object in previousMenu.
        -#
        -sub LoadPreviousMenuStateFile
        -    {
        -    my ($self) = @_;
        -
        -    my $fileIsOkay;
        -    my $version;
        -    my $previousStateFileName = NaturalDocs::Project->DataFile('PreviousMenuState.nd');
        -
        -    if (open(PREVIOUSSTATEFILEHANDLE, '<' . $previousStateFileName))
        -        {
        -        # See if it's binary.
        -        binmode(PREVIOUSSTATEFILEHANDLE);
        -
        -        my $firstChar;
        -        read(PREVIOUSSTATEFILEHANDLE, $firstChar, 1);
        -
        -        if ($firstChar == ::BINARY_FORMAT())
        -            {
        -            $version = NaturalDocs::Version->FromBinaryFile(\*PREVIOUSSTATEFILEHANDLE);
        -
        -            # Only the topic type format has changed since switching to binary, and we support both methods.
        -
        -            if (NaturalDocs::Version->CheckFileFormat($version))
        -                {  $fileIsOkay = 1;  }
        -            else
        -                {  close(PREVIOUSSTATEFILEHANDLE);  };
        -            }
        -
        -        else # it's not in binary
        -            {  close(PREVIOUSSTATEFILEHANDLE);  };
        -        };
        -
        -    if ($fileIsOkay)
        -        {
        -        if (NaturalDocs::Project->UserConfigFileStatus('Menu.txt') == ::FILE_CHANGED())
        -            {  $hasChanged = 1;  };
        -
        -
        -        my $menu = NaturalDocs::Menu::Entry->New(::MENU_GROUP(), undef, undef, undef);
        -        my $indexes = { };
        -        my $files = { };
        -
        -        my @groupStack;
        -        my $currentGroup = $menu;
        -        my $raw;
        -
        -        # [UInt8: type or 0 for end group]
        -
        -        while (read(PREVIOUSSTATEFILEHANDLE, $raw, 1))
        -            {
        -            my ($type, $flags, $title, $titleLength, $target, $targetLength);
        -            $type = unpack('C', $raw);
        -
        -            if ($type == 0)
        -                {  $currentGroup = pop @groupStack;  }
        -
        -            elsif ($type == ::MENU_FILE())
        -                {
        -                # [UInt8: noAutoTitle] [AString16: title] [AString16: target]
        -
        -                read(PREVIOUSSTATEFILEHANDLE, $raw, 3);
        -                (my $noAutoTitle, $titleLength) = unpack('Cn', $raw);
        -
        -                if ($noAutoTitle)
        -                    {  $flags = ::MENU_FILE_NOAUTOTITLE();  };
        -
        -                read(PREVIOUSSTATEFILEHANDLE, $title, $titleLength);
        -                read(PREVIOUSSTATEFILEHANDLE, $raw, 2);
        -
        -                $targetLength = unpack('n', $raw);
        -
        -                read(PREVIOUSSTATEFILEHANDLE, $target, $targetLength);
        -                }
        -
        -            elsif ($type == ::MENU_GROUP())
        -                {
        -                # [AString16: title]
        -
        -                read(PREVIOUSSTATEFILEHANDLE, $raw, 2);
        -                $titleLength = unpack('n', $raw);
        -
        -                read(PREVIOUSSTATEFILEHANDLE, $title, $titleLength);
        -                }
        -
        -            elsif ($type == ::MENU_INDEX())
        -                {
        -                # [AString16: title]
        -
        -                read(PREVIOUSSTATEFILEHANDLE, $raw, 2);
        -                $titleLength = unpack('n', $raw);
        -
        -                read(PREVIOUSSTATEFILEHANDLE, $title, $titleLength);
        -
        -                if ($version >= NaturalDocs::Version->FromString('1.3'))
        -                    {
        -                    # [AString16: topic type]
        -                    read(PREVIOUSSTATEFILEHANDLE, $raw, 2);
        -                    $targetLength = unpack('n', $raw);
        -
        -                    read(PREVIOUSSTATEFILEHANDLE, $target, $targetLength);
        -                    }
        -                else
        -                    {
        -                    # [UInt8: topic type (0 for general)]
        -                    read(PREVIOUSSTATEFILEHANDLE, $raw, 1);
        -                    $target = unpack('C', $raw);
        -
        -                    $target = NaturalDocs::Topics->TypeFromLegacy($target);
        -                    };
        -                }
        -
        -            elsif ($type == ::MENU_LINK())
        -                {
        -                # [AString16: title] [AString16: url]
        -
        -                read(PREVIOUSSTATEFILEHANDLE, $raw, 2);
        -                $titleLength = unpack('n', $raw);
        -
        -                read(PREVIOUSSTATEFILEHANDLE, $title, $titleLength);
        -                read(PREVIOUSSTATEFILEHANDLE, $raw, 2);
        -                $targetLength = unpack('n', $raw);
        -
        -                read(PREVIOUSSTATEFILEHANDLE, $target, $targetLength);
        -                }
        -
        -            elsif ($type == ::MENU_TEXT())
        -                {
        -                # [AString16: text]
        -
        -                read(PREVIOUSSTATEFILEHANDLE, $raw, 2);
        -                $titleLength = unpack('n', $raw);
        -
        -                read(PREVIOUSSTATEFILEHANDLE, $title, $titleLength);
        -                };
        -
        -
        -            # The topic type of the index may have been removed.
        -
        -            if ( !($type == ::MENU_INDEX() && !NaturalDocs::Topics->IsValidType($target)) )
        -                {
        -                my $entry = NaturalDocs::Menu::Entry->New($type, $title, $target, ($flags || 0));
        -                $currentGroup->PushToGroup($entry);
        -
        -                if ($type == ::MENU_FILE())
        -                    {
        -                    $files->{$target} = $entry;
        -                    }
        -                elsif ($type == ::MENU_GROUP())
        -                    {
        -                    push @groupStack, $currentGroup;
        -                    $currentGroup = $entry;
        -                    }
        -                elsif ($type == ::MENU_INDEX())
        -                    {
        -                    $indexes->{$target} = 1;
        -                    };
        -                };
        -
        -            };
        -
        -        close(PREVIOUSSTATEFILEHANDLE);
        -
        -        return ($menu, $indexes, $files);
        -        }
        -    else
        -        {
        -        $hasChanged = 1;
        -        return ( );
        -        };
        -    };
        -
        -
        -#
        -#   Function: SavePreviousMenuStateFile
        -#
        -#   Saves changes to <PreviousMenuState.nd>.
        -#
        -sub SavePreviousMenuStateFile
        -    {
        -    my ($self) = @_;
        -
        -    open (PREVIOUSSTATEFILEHANDLE, '>' . NaturalDocs::Project->DataFile('PreviousMenuState.nd'))
        -        or die "Couldn't save " . NaturalDocs::Project->DataFile('PreviousMenuState.nd') . ".\n";
        -
        -    binmode(PREVIOUSSTATEFILEHANDLE);
        -
        -    print PREVIOUSSTATEFILEHANDLE '' . ::BINARY_FORMAT();
        -
        -    NaturalDocs::Version->ToBinaryFile(\*PREVIOUSSTATEFILEHANDLE, NaturalDocs::Settings->AppVersion());
        -
        -    $self->WritePreviousMenuStateEntries($menu->GroupContent(), \*PREVIOUSSTATEFILEHANDLE);
        -
        -    close(PREVIOUSSTATEFILEHANDLE);
        -    };
        -
        -
        -#
        -#   Function: WritePreviousMenuStateEntries
        -#
        -#   A recursive function to write the contents of an arrayref of <NaturalDocs::Menu::Entry> objects to disk.
        -#
        -#   Parameters:
        -#
        -#       entries          - The arrayref of menu entries to write.
        -#       fileHandle      - The handle to the output file.
        -#
        -sub WritePreviousMenuStateEntries #(entries, fileHandle)
        -    {
        -    my ($self, $entries, $fileHandle) = @_;
        -
        -    foreach my $entry (@$entries)
        -        {
        -        if ($entry->Type() == ::MENU_FILE())
        -            {
        -            # We need to do length manually instead of using n/A in the template because it's not supported in earlier versions
        -            # of Perl.
        -
        -            # [UInt8: MENU_FILE] [UInt8: noAutoTitle] [AString16: title] [AString16: target]
        -            print $fileHandle pack('CCnA*nA*', ::MENU_FILE(), ($entry->Flags() & ::MENU_FILE_NOAUTOTITLE() ? 1 : 0),
        -                                                                length($entry->Title()), $entry->Title(),
        -                                                                length($entry->Target()), $entry->Target());
        -            }
        -
        -        elsif ($entry->Type() == ::MENU_GROUP())
        -            {
        -            # [UInt8: MENU_GROUP] [AString16: title]
        -            print $fileHandle pack('CnA*', ::MENU_GROUP(), length($entry->Title()), $entry->Title());
        -            $self->WritePreviousMenuStateEntries($entry->GroupContent(), $fileHandle);
        -            print $fileHandle pack('C', 0);
        -            }
        -
        -        elsif ($entry->Type() == ::MENU_INDEX())
        -            {
        -            # [UInt8: MENU_INDEX] [AString16: title] [AString16: topic type]
        -            print $fileHandle pack('CnA*nA*', ::MENU_INDEX(), length($entry->Title()), $entry->Title(),
        -                                                                                       length($entry->Target()), $entry->Target());
        -            }
        -
        -        elsif ($entry->Type() == ::MENU_LINK())
        -            {
        -            # [UInt8: MENU_LINK] [AString16: title] [AString16: url]
        -            print $fileHandle pack('CnA*nA*', ::MENU_LINK(), length($entry->Title()), $entry->Title(),
        -                                                             length($entry->Target()), $entry->Target());
        -            }
        -
        -        elsif ($entry->Type() == ::MENU_TEXT())
        -            {
        -            # [UInt8: MENU_TEXT] [AString16: hext]
        -            print $fileHandle pack('CnA*', ::MENU_TEXT(), length($entry->Title()), $entry->Title());
        -            };
        -        };
        -
        -    };
        -
        -
        -#
        -#   Function: CheckForTrashedMenu
        -#
        -#   Checks the menu to see if a significant number of file entries didn't resolve to actual files, and if so, saves a backup of the
        -#   menu and issues a warning.
        -#
        -#   Parameters:
        -#
        -#       numberOriginallyInMenu - A count of how many file entries were in the menu orignally.
        -#       numberRemoved - A count of how many file entries were removed from the menu.
        -#
        -sub CheckForTrashedMenu #(numberOriginallyInMenu, numberRemoved)
        -    {
        -    my ($self, $numberOriginallyInMenu, $numberRemoved) = @_;
        -
        -    no integer;
        -
        -    if ( ($numberOriginallyInMenu >= 6 && $numberRemoved == $numberOriginallyInMenu) ||
        -         ($numberOriginallyInMenu >= 12 && ($numberRemoved / $numberOriginallyInMenu) >= 0.4) ||
        -         ($numberRemoved >= 15) )
        -        {
        -        my $backupFile = NaturalDocs::Project->UserConfigFile('Menu_Backup.txt');
        -        my $backupFileNumber = 1;
        -
        -        while (-e $backupFile)
        -            {
        -            $backupFileNumber++;
        -            $backupFile = NaturalDocs::Project->UserConfigFile('Menu_Backup_' . $backupFileNumber . '.txt');
        -            };
        -
        -        NaturalDocs::File->Copy( NaturalDocs::Project->UserConfigFile('Menu.txt'), $backupFile );
        -
        -        print STDERR
        -        "\n"
        -        # GNU format.  See http://www.gnu.org/prep/standards_15.html
        -        . "NaturalDocs: warning: possible trashed menu\n"
        -        . "\n"
        -        . "   Natural Docs has detected that a significant number file entries in the\n"
        -        . "   menu did not resolve to actual files.  A backup of your original menu file\n"
        -        . "   has been saved as\n"
        -        . "\n"
        -        . "   " . $backupFile . "\n"
        -        . "\n"
        -        . "   - If you recently deleted a lot of files from your project, you can safely\n"
        -        . "     ignore this message.  They have been deleted from the menu as well.\n"
        -        . "   - If you recently rearranged your source tree, you may want to restore your\n"
        -        . "     menu from the backup and do a search and replace to preserve your layout.\n"
        -        . "     Otherwise the position of any moved files will be reset.\n"
        -        . "   - If neither of these is the case, you may have gotten the -i parameter\n"
        -        . "     wrong in the command line.  You should definitely restore the backup and\n"
        -        . "     try again, because otherwise every file in your menu will be reset.\n"
        -        . "\n";
        -        };
        -
        -    use integer;
        -    };
        -
        -
        -#
        -#   Function: GenerateTimestampText
        -#
        -#   Generates <timestampText> from <timestampCode> with the current date.
        -#
        -sub GenerateTimestampText
        -    {
        -    my $self = shift;
        -
        -    my @longMonths = ( 'January', 'February', 'March', 'April', 'May', 'June',
        -                                   'July', 'August', 'September', 'October', 'November', 'December' );
        -    my @shortMonths = ( 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec' );
        -
        -    my (undef, undef, undef, $day, $month, $year) = localtime();
        -    $year += 1900;
        -
        -    my $longDay;
        -    if ($day % 10 == 1 && $day != 11)
        -        {  $longDay = $day . 'st';  }
        -    elsif ($day % 10 == 2 && $day != 12)
        -        {  $longDay = $day . 'nd';  }
        -    elsif ($day % 10 == 3 && $day != 13)
        -        {  $longDay = $day . 'rd';  }
        -    else
        -        {  $longDay = $day . 'th';  };
        -
        -
        -    $timestampText = $timestampCode;
        -
        -    $timestampText =~ s/(?<![a-z])month(?![a-z])/$longMonths[$month]/i;
        -    $timestampText =~ s/(?<![a-z])mon(?![a-z])/$shortMonths[$month]/i;
        -    $timestampText =~ s/(?<![a-z])mm(?![a-z])/sprintf('%02d', $month + 1)/ie;
        -    $timestampText =~ s/(?<![a-z])m(?![a-z])/$month + 1/ie;
        -
        -    $timestampText =~ s/(?<![a-z])day(?![a-z])/$longDay/i;
        -    $timestampText =~ s/(?<![a-z])dd(?![a-z])/sprintf('%02d', $day)/ie;
        -    $timestampText =~ s/(?<![a-z])d(?![a-z])/$day/i;
        -
        -    $timestampText =~ s/(?<![a-z])(?:year|yyyy)(?![a-z])/$year/i;
        -    $timestampText =~ s/(?<![a-z])yy(?![a-z])/sprintf('%02d', $year % 100)/ie;
        -    };
        -
        -
        -use constant CONVERT_PARENTHESIS => 0x01;
        -use constant CONVERT_COMMAS => 0x02;
        -use constant CONVERT_COLONS => 0x04;
        -
        -#
        -#   Function: ConvertAmpChars
        -#   Replaces certain characters in the string with their entities and returns it.
        -#
        -#   Parameters:
        -#
        -#       text - The text to convert.
        -#       flags - The flags of any additional characters to convert.
        -#
        -#   Flags:
        -#
        -#       - CONVERT_PARENTHESIS
        -#       - CONVERT_COMMAS
        -#       - CONVERT_COLONS
        -#
        -#   Returns:
        -#
        -#       The string with the amp chars converted.
        -#
        -sub ConvertAmpChars #(string text, int flags) => string
        -    {
        -    my ($self, $text, $flags) = @_;
        -
        -    $text =~ s/&/&amp;/g;
        -    $text =~ s/\{/&lbrace;/g;
        -    $text =~ s/\}/&rbrace;/g;
        -
        -    if ($flags & CONVERT_PARENTHESIS())
        -        {
        -        $text =~ s/\(/&lparen;/g;
        -        $text =~ s/\)/&rparen;/g;
        -        };
        -    if ($flags & CONVERT_COMMAS())
        -        {
        -        $text =~ s/\,/&comma;/g;
        -        };
        -    if ($flags & CONVERT_COLONS())
        -        {
        -        $text =~ s/\:/&colon;/g;
        -        };
        -
        -    return $text;
        -    };
        -
        -
        -#
        -#   Function: RestoreAmpChars
        -#   Replaces entity characters in the string with their original characters and returns it.  This will restore all amp chars regardless
        -#   of the flags passed to <ConvertAmpChars()>.
        -#
        -sub RestoreAmpChars #(string text) => string
        -    {
        -    my ($self, $text) = @_;
        -
        -    $text =~ s/&lparen;/(/gi;
        -    $text =~ s/&rparen;/)/gi;
        -    $text =~ s/&lbrace;/{/gi;
        -    $text =~ s/&rbrace;/}/gi;
        -    $text =~ s/&comma;/,/gi;
        -    $text =~ s/&amp;/&/gi;
        -    $text =~ s/&colon;/:/gi;
        -
        -    return $text;
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Auto-Adjustment Functions
        -
        -
        -#
        -#   Function: ResolveInputDirectories
        -#
        -#   Detects if the input directories in the menu file match those in the command line, and if not, tries to resolve them.  This allows
        -#   menu files to work across machines, since the absolute paths won't be the same but the relative ones should be.
        -#
        -#   Parameters:
        -#
        -#       inputDirectoryNames - A hashref of the input directories appearing in the menu file, or undef if none.  The keys are the
        -#                                        directories, and the values are their names.  May be undef.
        -#
        -sub ResolveInputDirectories #(inputDirectoryNames)
        -    {
        -    my ($self, $menuDirectoryNames) = @_;
        -
        -
        -    # Determine which directories don't match the command line, if any.
        -
        -    my $inputDirectories = NaturalDocs::Settings->InputDirectories();
        -    my @unresolvedMenuDirectories;
        -
        -    foreach my $menuDirectory (keys %$menuDirectoryNames)
        -        {
        -        my $found;
        -
        -        foreach my $inputDirectory (@$inputDirectories)
        -            {
        -            if ($menuDirectory eq $inputDirectory)
        -                {
        -                $found = 1;
        -                last;
        -                };
        -            };
        -
        -        if (!$found)
        -            {  push @unresolvedMenuDirectories, $menuDirectory;  };
        -        };
        -
        -    # Quit if everything matches up, which should be the most common case.
        -    if (!scalar @unresolvedMenuDirectories)
        -        {  return;  };
        -
        -    # Poop.  See which input directories are still available.
        -
        -    my @unresolvedInputDirectories;
        -
        -    foreach my $inputDirectory (@$inputDirectories)
        -        {
        -        if (!exists $menuDirectoryNames->{$inputDirectory})
        -            {  push @unresolvedInputDirectories, $inputDirectory;  };
        -        };
        -
        -    # Quit if there are none.  This means an input directory is in the menu that isn't in the command line.  Natural Docs should
        -    # proceed normally and let the files be deleted.
        -    if (!scalar @unresolvedInputDirectories)
        -        {
        -        $hasChanged = 1;
        -        return;
        -        };
        -
        -    # The index into menuDirectoryScores is the same as in unresolvedMenuDirectories.  The index into each arrayref within it is
        -    # the same as in unresolvedInputDirectories.
        -    my @menuDirectoryScores;
        -    for (my $i = 0; $i < scalar @unresolvedMenuDirectories; $i++)
        -        {  push @menuDirectoryScores, [ ];  };
        -
        -
        -    # Now plow through the menu, looking for files that have an unresolved base.
        -
        -    my @menuGroups = ( $menu );
        -
        -    while (scalar @menuGroups)
        -        {
        -        my $currentGroup = pop @menuGroups;
        -        my $currentGroupContent = $currentGroup->GroupContent();
        -
        -        foreach my $entry (@$currentGroupContent)
        -            {
        -            if ($entry->Type() == ::MENU_GROUP())
        -                {
        -                push @menuGroups, $entry;
        -                }
        -            elsif ($entry->Type() == ::MENU_FILE())
        -                {
        -                # Check if it uses an unresolved base.
        -                for (my $i = 0; $i < scalar @unresolvedMenuDirectories; $i++)
        -                    {
        -                    if (NaturalDocs::File->IsSubPathOf($unresolvedMenuDirectories[$i], $entry->Target()))
        -                        {
        -                        my $relativePath = NaturalDocs::File->MakeRelativePath($unresolvedMenuDirectories[$i], $entry->Target());
        -                        $self->ResolveFile($relativePath, \@unresolvedInputDirectories, $menuDirectoryScores[$i]);
        -                        last;
        -                        };
        -                    };
        -                };
        -            };
        -        };
        -
        -
        -    # Now, create an array of score objects.  Each score object is the three value arrayref [ from, to, score ].  From and To are the
        -    # conversion options and are the indexes into unresolvedInput/MenuDirectories.  We'll sort this array by score to get the best
        -    # possible conversions.  Yes, really.
        -    my @scores;
        -
        -    for (my $menuIndex = 0; $menuIndex < scalar @unresolvedMenuDirectories; $menuIndex++)
        -        {
        -        for (my $inputIndex = 0; $inputIndex < scalar @unresolvedInputDirectories; $inputIndex++)
        -            {
        -            if ($menuDirectoryScores[$menuIndex]->[$inputIndex])
        -                {
        -                push @scores, [ $menuIndex, $inputIndex, $menuDirectoryScores[$menuIndex]->[$inputIndex] ];
        -                };
        -            };
        -        };
        -
        -    @scores = sort { $b->[2] <=> $a->[2] } @scores;
        -
        -
        -    # Now we determine what goes where.
        -    my @menuDirectoryConversions;
        -
        -    foreach my $scoreObject (@scores)
        -        {
        -        if (!defined $menuDirectoryConversions[ $scoreObject->[0] ])
        -            {
        -            $menuDirectoryConversions[ $scoreObject->[0] ] = $unresolvedInputDirectories[ $scoreObject->[1] ];
        -            };
        -        };
        -
        -
        -    # Now, FINALLY, we do the conversion.  Note that not every menu directory may have a conversion defined.
        -
        -    @menuGroups = ( $menu );
        -
        -    while (scalar @menuGroups)
        -        {
        -        my $currentGroup = pop @menuGroups;
        -        my $currentGroupContent = $currentGroup->GroupContent();
        -
        -        foreach my $entry (@$currentGroupContent)
        -            {
        -            if ($entry->Type() == ::MENU_GROUP())
        -                {
        -                push @menuGroups, $entry;
        -                }
        -            elsif ($entry->Type() == ::MENU_FILE())
        -                {
        -                # Check if it uses an unresolved base.
        -                for (my $i = 0; $i < scalar @unresolvedMenuDirectories; $i++)
        -                    {
        -                    if (NaturalDocs::File->IsSubPathOf($unresolvedMenuDirectories[$i], $entry->Target()) &&
        -                        defined $menuDirectoryConversions[$i])
        -                        {
        -                        my $relativePath = NaturalDocs::File->MakeRelativePath($unresolvedMenuDirectories[$i], $entry->Target());
        -                        $entry->SetTarget( NaturalDocs::File->JoinPaths($menuDirectoryConversions[$i], $relativePath) );
        -                        last;
        -                        };
        -                    };
        -                };
        -            };
        -        };
        -
        -
        -    # Whew.
        -
        -    $hasChanged = 1;
        -    };
        -
        -
        -#
        -#   Function: ResolveRelativeInputDirectories
        -#
        -#   Resolves relative input directories to the input directories available.
        -#
        -sub ResolveRelativeInputDirectories
        -    {
        -    my ($self) = @_;
        -
        -    my $inputDirectories = NaturalDocs::Settings->InputDirectories();
        -    my $resolvedInputDirectory;
        -
        -    if (scalar @$inputDirectories == 1)
        -        {  $resolvedInputDirectory = $inputDirectories->[0];  }
        -    else
        -        {
        -        my @score;
        -
        -        # Plow through the menu, looking for files and scoring them.
        -
        -        my @menuGroups = ( $menu );
        -
        -        while (scalar @menuGroups)
        -            {
        -            my $currentGroup = pop @menuGroups;
        -            my $currentGroupContent = $currentGroup->GroupContent();
        -
        -            foreach my $entry (@$currentGroupContent)
        -                {
        -                if ($entry->Type() == ::MENU_GROUP())
        -                    {
        -                    push @menuGroups, $entry;
        -                    }
        -                elsif ($entry->Type() == ::MENU_FILE())
        -                    {
        -                    $self->ResolveFile($entry->Target(), $inputDirectories, \@score);
        -                    };
        -                };
        -            };
        -
        -        # Determine the best match.
        -
        -        my $bestScore = 0;
        -        my $bestIndex = 0;
        -
        -        for (my $i = 0; $i < scalar @$inputDirectories; $i++)
        -            {
        -            if ($score[$i] > $bestScore)
        -                {
        -                $bestScore = $score[$i];
        -                $bestIndex = $i;
        -                };
        -            };
        -
        -        $resolvedInputDirectory = $inputDirectories->[$bestIndex];
        -        };
        -
        -
        -    # Okay, now that we have our resolved directory, update everything.
        -
        -    my @menuGroups = ( $menu );
        -
        -    while (scalar @menuGroups)
        -        {
        -        my $currentGroup = pop @menuGroups;
        -        my $currentGroupContent = $currentGroup->GroupContent();
        -
        -        foreach my $entry (@$currentGroupContent)
        -            {
        -            if ($entry->Type() == ::MENU_GROUP())
        -                {  push @menuGroups, $entry;  }
        -            elsif ($entry->Type() == ::MENU_FILE())
        -                {
        -                $entry->SetTarget( NaturalDocs::File->JoinPaths($resolvedInputDirectory, $entry->Target()) );
        -                };
        -            };
        -        };
        -
        -    if (scalar @$inputDirectories > 1)
        -        {  $hasChanged = 1;  };
        -
        -    return $resolvedInputDirectory;
        -    };
        -
        -
        -#
        -#   Function: ResolveFile
        -#
        -#   Tests a relative path against a list of directories.  Adds one to the score of each base where there is a match.
        -#
        -#   Parameters:
        -#
        -#       relativePath - The relative file name to test.
        -#       possibleBases - An arrayref of bases to test it against.
        -#       possibleBaseScores - An arrayref of scores to adjust.  The score indexes should correspond to the base indexes.
        -#
        -sub ResolveFile #(relativePath, possibleBases, possibleBaseScores)
        -    {
        -    my ($self, $relativePath, $possibleBases, $possibleBaseScores) = @_;
        -
        -    for (my $i = 0; $i < scalar @$possibleBases; $i++)
        -        {
        -        if (-e NaturalDocs::File->JoinPaths($possibleBases->[$i], $relativePath))
        -            {  $possibleBaseScores->[$i]++;  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: LockUserTitleChanges
        -#
        -#   Detects if the user manually changed any file titles, and if so, automatically locks them with <MENU_FILE_NOAUTOTITLE>.
        -#
        -#   Parameters:
        -#
        -#       previousMenuFiles - A hashref of the files from the previous menu state.  The keys are the <FileNames>, and the values are
        -#                                    references to their <NaturalDocs::Menu::Entry> objects.
        -#
        -sub LockUserTitleChanges #(previousMenuFiles)
        -    {
        -    my ($self, $previousMenuFiles) = @_;
        -
        -    my @groupStack = ( $menu );
        -    my $groupEntry;
        -
        -    while (scalar @groupStack)
        -        {
        -        $groupEntry = pop @groupStack;
        -
        -        foreach my $entry (@{$groupEntry->GroupContent()})
        -            {
        -
        -            # If it's an unlocked file entry
        -            if ($entry->Type() == ::MENU_FILE() && ($entry->Flags() & ::MENU_FILE_NOAUTOTITLE()) == 0)
        -                {
        -                my $previousEntry = $previousMenuFiles->{$entry->Target()};
        -
        -                # If the previous entry was also unlocked and the titles are different, the user changed the title.  Automatically lock it.
        -                if (defined $previousEntry && ($previousEntry->Flags() & ::MENU_FILE_NOAUTOTITLE()) == 0 &&
        -                    $entry->Title() ne $previousEntry->Title())
        -                    {
        -                    $entry->SetFlags($entry->Flags() | ::MENU_FILE_NOAUTOTITLE());
        -                    $hasChanged = 1;
        -                    };
        -                }
        -
        -            elsif ($entry->Type() == ::MENU_GROUP())
        -                {
        -                push @groupStack, $entry;
        -                };
        -
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: FlagAutoTitleChanges
        -#
        -#   Finds which files have auto-titles that changed and flags their groups for updating with <MENU_GROUP_UPDATETITLES> and
        -#   <MENU_GROUP_UPDATEORDER>.
        -#
        -sub FlagAutoTitleChanges
        -    {
        -    my ($self) = @_;
        -
        -    my @groupStack = ( $menu );
        -    my $groupEntry;
        -
        -    while (scalar @groupStack)
        -        {
        -        $groupEntry = pop @groupStack;
        -
        -        foreach my $entry (@{$groupEntry->GroupContent()})
        -            {
        -            if ($entry->Type() == ::MENU_FILE() && ($entry->Flags() & ::MENU_FILE_NOAUTOTITLE()) == 0 &&
        -                exists $defaultTitlesChanged{$entry->Target()})
        -                {
        -                $groupEntry->SetFlags($groupEntry->Flags() | ::MENU_GROUP_UPDATETITLES() | ::MENU_GROUP_UPDATEORDER());
        -                $hasChanged = 1;
        -                }
        -            elsif ($entry->Type() == ::MENU_GROUP())
        -                {
        -                push @groupStack, $entry;
        -                };
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: AutoPlaceNewFiles
        -#
        -#   Adds files to the menu that aren't already on it, attempting to guess where they belong.
        -#
        -#   New files are placed after a dummy <MENU_ENDOFORIGINAL> entry so that they don't affect the detected order.  Also, the
        -#   groups they're placed in get <MENU_GROUP_UPDATETITLES>, <MENU_GROUP_UPDATESTRUCTURE>, and
        -#   <MENU_GROUP_UPDATEORDER> flags.
        -#
        -#   Parameters:
        -#
        -#       filesInMenu - An existence hash of all the <FileNames> present in the menu.
        -#
        -sub AutoPlaceNewFiles #(fileInMenu)
        -    {
        -    my ($self, $filesInMenu) = @_;
        -
        -    my $files = NaturalDocs::Project->FilesWithContent();
        -
        -    my $directories;
        -
        -    foreach my $file (keys %$files)
        -        {
        -        if (!exists $filesInMenu->{$file})
        -            {
        -            # This is done on demand because new files shouldn't be added very often, so this will save time.
        -            if (!defined $directories)
        -                {  $directories = $self->MatchDirectoriesAndGroups();  };
        -
        -            my $targetGroup;
        -            my $fileDirectoryString = (NaturalDocs::File->SplitPath($file))[1];
        -
        -            $targetGroup = $directories->{$fileDirectoryString};
        -
        -            if (!defined $targetGroup)
        -                {
        -                # Okay, if there's no exact match, work our way down.
        -
        -                my @fileDirectories = NaturalDocs::File->SplitDirectories($fileDirectoryString);
        -
        -                do
        -                    {
        -                    pop @fileDirectories;
        -                    $targetGroup = $directories->{ NaturalDocs::File->JoinDirectories(@fileDirectories) };
        -                    }
        -                while (!defined $targetGroup && scalar @fileDirectories);
        -
        -                if (!defined $targetGroup)
        -                    {  $targetGroup = $menu;  };
        -                };
        -
        -            $targetGroup->MarkEndOfOriginal();
        -            $targetGroup->PushToGroup( NaturalDocs::Menu::Entry->New(::MENU_FILE(), undef, $file, undef) );
        -
        -            $targetGroup->SetFlags( $targetGroup->Flags() | ::MENU_GROUP_UPDATETITLES() |
        -                                                 ::MENU_GROUP_UPDATESTRUCTURE() | ::MENU_GROUP_UPDATEORDER() );
        -
        -            $hasChanged = 1;
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: MatchDirectoriesAndGroups
        -#
        -#   Determines which groups files in certain directories should be placed in.
        -#
        -#   Returns:
        -#
        -#       A hashref.  The keys are the directory names, and the values are references to the group objects they should be placed in.
        -#
        -#       This only repreesents directories that currently have files on the menu, so it shouldn't be assumed that every possible
        -#       directory will exist.  To match, you should first try to match the directory, and then strip the deepest directories one by
        -#       one until there's a match or there's none left.  If there's none left, use the root group <menu>.
        -#
        -sub MatchDirectoriesAndGroups
        -    {
        -    my ($self) = @_;
        -
        -    # The keys are the directory names, and the values are hashrefs.  For the hashrefs, the keys are the group objects, and the
        -    # values are the number of files in them from that directory.  In other words,
        -    # $directories{$directory}->{$groupEntry} = $count;
        -    my %directories;
        -    # Note that we need to use Tie::RefHash to use references as keys.  Won't work otherwise.  Also, not every Perl distro comes
        -    # with Tie::RefHash::Nestable, so we can't rely on that.
        -
        -    # We're using an index instead of pushing and popping because we want to save a list of the groups in the order they appear
        -    # to break ties.
        -    my @groups = ( $menu );
        -    my $groupIndex = 0;
        -
        -
        -    # Count the number of files in each group that appear in each directory.
        -
        -    while ($groupIndex < scalar @groups)
        -        {
        -        my $groupEntry = $groups[$groupIndex];
        -
        -        foreach my $entry (@{$groupEntry->GroupContent()})
        -            {
        -            if ($entry->Type() == ::MENU_GROUP())
        -                {
        -                push @groups, $entry;
        -                }
        -            elsif ($entry->Type() == ::MENU_FILE())
        -                {
        -                my $directory = (NaturalDocs::File->SplitPath($entry->Target()))[1];
        -
        -                if (!exists $directories{$directory})
        -                    {
        -                    my $subHash = { };
        -                    tie %$subHash, 'Tie::RefHash';
        -                    $directories{$directory} = $subHash;
        -                    };
        -
        -                if (!exists $directories{$directory}->{$groupEntry})
        -                    {  $directories{$directory}->{$groupEntry} = 1;  }
        -                else
        -                    {  $directories{$directory}->{$groupEntry}++;  };
        -                };
        -            };
        -
        -        $groupIndex++;
        -        };
        -
        -
        -    # Determine which group goes with which directory, breaking ties by using whichever group appears first.
        -
        -    my $finalDirectories = { };
        -
        -    while (my ($directory, $directoryGroups) = each %directories)
        -        {
        -        my $bestGroup;
        -        my $bestCount = 0;
        -        my %tiedGroups;  # Existence hash
        -
        -        while (my ($group, $count) = each %$directoryGroups)
        -            {
        -            if ($count > $bestCount)
        -                {
        -                $bestGroup = $group;
        -                $bestCount = $count;
        -                %tiedGroups = ( );
        -                }
        -            elsif ($count == $bestCount)
        -                {
        -                $tiedGroups{$group} = 1;
        -                };
        -            };
        -
        -        # Break ties.
        -        if (scalar keys %tiedGroups)
        -            {
        -            $tiedGroups{$bestGroup} = 1;
        -
        -            foreach my $group (@groups)
        -                {
        -                if (exists $tiedGroups{$group})
        -                    {
        -                    $bestGroup = $group;
        -                    last;
        -                    };
        -                };
        -            };
        -
        -
        -        $finalDirectories->{$directory} = $bestGroup;
        -        };
        -
        -
        -    return $finalDirectories;
        -    };
        -
        -
        -#
        -#   Function: RemoveDeadFiles
        -#
        -#   Removes files from the menu that no longer exist or no longer have Natural Docs content.
        -#
        -#   Returns:
        -#
        -#       The number of file entries removed.
        -#
        -sub RemoveDeadFiles
        -    {
        -    my ($self) = @_;
        -
        -    my @groupStack = ( $menu );
        -    my $numberRemoved = 0;
        -
        -    my $filesWithContent = NaturalDocs::Project->FilesWithContent();
        -
        -    while (scalar @groupStack)
        -        {
        -        my $groupEntry = pop @groupStack;
        -        my $groupContent = $groupEntry->GroupContent();
        -
        -        my $index = 0;
        -        while ($index < scalar @$groupContent)
        -            {
        -            if ($groupContent->[$index]->Type() == ::MENU_FILE() &&
        -                !exists $filesWithContent->{ $groupContent->[$index]->Target() } )
        -                {
        -                $groupEntry->DeleteFromGroup($index);
        -
        -                $groupEntry->SetFlags( $groupEntry->Flags() | ::MENU_GROUP_UPDATETITLES() |
        -                                                   ::MENU_GROUP_UPDATESTRUCTURE() );
        -                $numberRemoved++;
        -                $hasChanged = 1;
        -                }
        -
        -            elsif ($groupContent->[$index]->Type() == ::MENU_GROUP())
        -                {
        -                push @groupStack, $groupContent->[$index];
        -                $index++;
        -                }
        -
        -            else
        -                {  $index++;  };
        -            };
        -        };
        -
        -    return $numberRemoved;
        -    };
        -
        -
        -#
        -#   Function: BanAndUnbanIndexes
        -#
        -#   Adjusts the indexes that are banned depending on if the user added or deleted any.
        -#
        -sub BanAndUnbanIndexes
        -    {
        -    my ($self) = @_;
        -
        -    # Unban any indexes that are present, meaning the user added them back manually without deleting the ban.
        -    foreach my $index (keys %indexes)
        -        {  delete $bannedIndexes{$index};  };
        -
        -    # Ban any indexes that were in the previous menu but not the current, meaning the user manually deleted them.  However,
        -    # don't do this if the topic isn't indexable, meaning they changed the topic type rather than the menu.
        -    foreach my $index (keys %previousIndexes)
        -        {
        -        if (!exists $indexes{$index} && NaturalDocs::Topics->TypeInfo($index)->Index())
        -            {  $bannedIndexes{$index} = 1;  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: AddAndRemoveIndexes
        -#
        -#   Automatically adds and removes index entries on the menu as necessary.  <DetectIndexGroups()> should be called
        -#   beforehand.
        -#
        -sub AddAndRemoveIndexes
        -    {
        -    my ($self) = @_;
        -
        -    my %validIndexes;
        -    my @allIndexes = NaturalDocs::Topics->AllIndexableTypes();
        -
        -    foreach my $index (@allIndexes)
        -        {
        -        # Strip the banned indexes first so it's potentially less work for SymbolTable.
        -        if (!exists $bannedIndexes{$index})
        -            {  $validIndexes{$index} = 1;  };
        -        };
        -
        -    %validIndexes = %{NaturalDocs::SymbolTable->HasIndexes(\%validIndexes)};
        -
        -
        -    # Delete dead indexes and find the best index group.
        -
        -    my @groupStack = ( $menu );
        -
        -    my $bestIndexGroup;
        -    my $bestIndexCount = 0;
        -
        -    while (scalar @groupStack)
        -        {
        -        my $currentGroup = pop @groupStack;
        -        my $index = 0;
        -
        -        my $currentIndexCount = 0;
        -
        -        while ($index < scalar @{$currentGroup->GroupContent()})
        -            {
        -            my $entry = $currentGroup->GroupContent()->[$index];
        -
        -            if ($entry->Type() == ::MENU_INDEX())
        -                {
        -                $currentIndexCount++;
        -
        -                if ($currentIndexCount > $bestIndexCount)
        -                    {
        -                    $bestIndexCount = $currentIndexCount;
        -                    $bestIndexGroup = $currentGroup;
        -                    };
        -
        -                # Remove it if it's dead.
        -
        -                if (!exists $validIndexes{ $entry->Target() })
        -                    {
        -                    $currentGroup->DeleteFromGroup($index);
        -                    delete $indexes{ $entry->Target() };
        -                    $hasChanged = 1;
        -                    }
        -                else
        -                    {  $index++;  };
        -                }
        -
        -            else
        -                {
        -                if ($entry->Type() == ::MENU_GROUP())
        -                    {  push @groupStack, $entry;  };
        -
        -                $index++;
        -                };
        -            };
        -        };
        -
        -
        -    # Now add the new indexes.
        -
        -    foreach my $index (keys %indexes)
        -        {  delete $validIndexes{$index};  };
        -
        -    if (scalar keys %validIndexes)
        -        {
        -        # Add a group if there are no indexes at all.
        -
        -        if ($bestIndexCount == 0)
        -            {
        -            $menu->MarkEndOfOriginal();
        -
        -            my $newIndexGroup = NaturalDocs::Menu::Entry->New(::MENU_GROUP(), 'Index', undef,
        -                                                                                              ::MENU_GROUP_ISINDEXGROUP());
        -            $menu->PushToGroup($newIndexGroup);
        -
        -            $bestIndexGroup = $newIndexGroup;
        -            $menu->SetFlags( $menu->Flags() | ::MENU_GROUP_UPDATEORDER() | ::MENU_GROUP_UPDATESTRUCTURE() );
        -            };
        -
        -        # Add the new indexes.
        -
        -        $bestIndexGroup->MarkEndOfOriginal();
        -        my $isIndexGroup = $bestIndexGroup->Flags() & ::MENU_GROUP_ISINDEXGROUP();
        -
        -        foreach my $index (keys %validIndexes)
        -            {
        -            my $title;
        -
        -            if ($isIndexGroup)
        -                {
        -                if ($index eq ::TOPIC_GENERAL())
        -                    {  $title = 'Everything';  }
        -                else
        -                    {  $title = NaturalDocs::Topics->NameOfType($index, 1);  };
        -                }
        -            else
        -                {
        -                $title = NaturalDocs::Topics->NameOfType($index) . ' Index';
        -                };
        -
        -            my $newEntry = NaturalDocs::Menu::Entry->New(::MENU_INDEX(), $title, $index, undef);
        -            $bestIndexGroup->PushToGroup($newEntry);
        -
        -            $indexes{$index} = 1;
        -            };
        -
        -        $bestIndexGroup->SetFlags( $bestIndexGroup->Flags() |
        -                                                   ::MENU_GROUP_UPDATEORDER() | ::MENU_GROUP_UPDATESTRUCTURE() );
        -        $hasChanged = 1;
        -        };
        -    };
        -
        -
        -#
        -#   Function: RemoveDeadGroups
        -#
        -#   Removes groups with less than two entries.  It will always remove empty groups, and it will remove groups with one entry if it
        -#   has the <MENU_GROUP_UPDATESTRUCTURE> flag.
        -#
        -sub RemoveDeadGroups
        -    {
        -    my ($self) = @_;
        -
        -    my $index = 0;
        -
        -    while ($index < scalar @{$menu->GroupContent()})
        -        {
        -        my $entry = $menu->GroupContent()->[$index];
        -
        -        if ($entry->Type() == ::MENU_GROUP())
        -            {
        -            my $removed = $self->RemoveIfDead($entry, $menu, $index);
        -
        -            if (!$removed)
        -                {  $index++;  };
        -            }
        -        else
        -            {  $index++;  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: RemoveIfDead
        -#
        -#   Checks a group and all its sub-groups for life and remove any that are dead.  Empty groups are removed, and groups with one
        -#   entry and the <MENU_GROUP_UPDATESTRUCTURE> flag have their entry moved to the parent group.
        -#
        -#   Parameters:
        -#
        -#       groupEntry - The group to check for possible deletion.
        -#       parentGroupEntry - The parent group to move the single entry to if necessary.
        -#       parentGroupIndex - The index of the group in its parent.
        -#
        -#   Returns:
        -#
        -#       Whether the group was removed or not.
        -#
        -sub RemoveIfDead #(groupEntry, parentGroupEntry, parentGroupIndex)
        -    {
        -    my ($self, $groupEntry, $parentGroupEntry, $parentGroupIndex) = @_;
        -
        -
        -    # Do all sub-groups first, since their deletions will affect our UPDATESTRUCTURE flag and content count.
        -
        -    my $index = 0;
        -    while ($index < scalar @{$groupEntry->GroupContent()})
        -        {
        -        my $entry = $groupEntry->GroupContent()->[$index];
        -
        -        if ($entry->Type() == ::MENU_GROUP())
        -            {
        -            my $removed = $self->RemoveIfDead($entry, $groupEntry, $index);
        -
        -            if (!$removed)
        -                {  $index++;  };
        -            }
        -        else
        -            {  $index++;  };
        -        };
        -
        -
        -    # Now check ourself.
        -
        -    my $count = scalar @{$groupEntry->GroupContent()};
        -    if ($groupEntry->Flags() & ::MENU_GROUP_HASENDOFORIGINAL())
        -        {  $count--;  };
        -
        -    if ($count == 0)
        -        {
        -        $parentGroupEntry->DeleteFromGroup($parentGroupIndex);
        -
        -        $parentGroupEntry->SetFlags( $parentGroupEntry->Flags() | ::MENU_GROUP_UPDATESTRUCTURE() );
        -
        -        $hasChanged = 1;
        -        return 1;
        -        }
        -    elsif ($count == 1 && ($groupEntry->Flags() & ::MENU_GROUP_UPDATESTRUCTURE()) )
        -        {
        -        my $onlyEntry = $groupEntry->GroupContent()->[0];
        -        if ($onlyEntry->Type() == ::MENU_ENDOFORIGINAL())
        -            {  $onlyEntry = $groupEntry->GroupContent()->[1];  };
        -
        -        $parentGroupEntry->DeleteFromGroup($parentGroupIndex);
        -
        -        $parentGroupEntry->MarkEndOfOriginal();
        -        $parentGroupEntry->PushToGroup($onlyEntry);
        -
        -        $parentGroupEntry->SetFlags( $parentGroupEntry->Flags() | ::MENU_GROUP_UPDATETITLES() |
        -                                                     ::MENU_GROUP_UPDATEORDER() | ::MENU_GROUP_UPDATESTRUCTURE() );
        -
        -        $hasChanged = 1;
        -        return 1;
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: DetectIndexGroups
        -#
        -#   Finds groups that are primarily used for indexes and gives them the <MENU_GROUP_ISINDEXGROUP> flag.
        -#
        -sub DetectIndexGroups
        -    {
        -    my ($self) = @_;
        -
        -    my @groupStack = ( $menu );
        -
        -    while (scalar @groupStack)
        -        {
        -        my $groupEntry = pop @groupStack;
        -
        -        my $isIndexGroup = -1;  # -1: Can't tell yet.  0: Can't be an index group.  1: Is an index group so far.
        -
        -        foreach my $entry (@{$groupEntry->GroupContent()})
        -            {
        -            if ($entry->Type() == ::MENU_INDEX())
        -                {
        -                if ($isIndexGroup == -1)
        -                    {  $isIndexGroup = 1;  };
        -                }
        -
        -            # Text is tolerated, but it still needs at least one index entry.
        -            elsif ($entry->Type() != ::MENU_TEXT())
        -                {
        -                $isIndexGroup = 0;
        -
        -                if ($entry->Type() == ::MENU_GROUP())
        -                    {  push @groupStack, $entry;  };
        -                };
        -            };
        -
        -        if ($isIndexGroup == 1)
        -            {
        -            $groupEntry->SetFlags( $groupEntry->Flags() | ::MENU_GROUP_ISINDEXGROUP() );
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: CreateDirectorySubGroups
        -#
        -#   Where possible, creates sub-groups based on directories for any long groups that have <MENU_GROUP_UPDATESTRUCTURE>
        -#   set.  Clears the flag afterwards on groups that are short enough to not need any more sub-groups, but leaves it for the rest.
        -#
        -sub CreateDirectorySubGroups
        -    {
        -    my ($self) = @_;
        -
        -    my @groupStack = ( $menu );
        -
        -    foreach my $groupEntry (@groupStack)
        -        {
        -        if ($groupEntry->Flags() & ::MENU_GROUP_UPDATESTRUCTURE())
        -            {
        -            # Count the number of files.
        -
        -            my $fileCount = 0;
        -
        -            foreach my $entry (@{$groupEntry->GroupContent()})
        -                {
        -                if ($entry->Type() == ::MENU_FILE())
        -                    {  $fileCount++;  };
        -                };
        -
        -
        -            if ($fileCount > MAXFILESINGROUP)
        -                {
        -                my @sharedDirectories = $self->SharedDirectoriesOf($groupEntry);
        -                my $unsharedIndex = scalar @sharedDirectories;
        -
        -                # The keys are the first directory entries after the shared ones, and the values are the number of files that are in
        -                # that directory.  Files that don't have subdirectories after the shared directories aren't included because they shouldn't
        -                # be put in a subgroup.
        -                my %directoryCounts;
        -
        -                foreach my $entry (@{$groupEntry->GroupContent()})
        -                    {
        -                    if ($entry->Type() == ::MENU_FILE())
        -                        {
        -                        my @entryDirectories = NaturalDocs::File->SplitDirectories( (NaturalDocs::File->SplitPath($entry->Target()))[1] );
        -
        -                        if (scalar @entryDirectories > $unsharedIndex)
        -                            {
        -                            my $unsharedDirectory = $entryDirectories[$unsharedIndex];
        -
        -                            if (!exists $directoryCounts{$unsharedDirectory})
        -                                {  $directoryCounts{$unsharedDirectory} = 1;  }
        -                            else
        -                                {  $directoryCounts{$unsharedDirectory}++;  };
        -                            };
        -                        };
        -                    };
        -
        -
        -                # Now create the subgroups.
        -
        -                # The keys are the first directory entries after the shared ones, and the values are the groups for those files to be
        -                # put in.  There will only be entries for the groups with at least MINFILESINNEWGROUP files.
        -                my %directoryGroups;
        -
        -                while (my ($directory, $count) = each %directoryCounts)
        -                    {
        -                    if ($count >= MINFILESINNEWGROUP)
        -                        {
        -                        my $newGroup = NaturalDocs::Menu::Entry->New( ::MENU_GROUP(), ucfirst($directory), undef,
        -                                                                                                   ::MENU_GROUP_UPDATETITLES() |
        -                                                                                                   ::MENU_GROUP_UPDATEORDER() );
        -
        -                        if ($count > MAXFILESINGROUP)
        -                            {  $newGroup->SetFlags( $newGroup->Flags() | ::MENU_GROUP_UPDATESTRUCTURE());  };
        -
        -                        $groupEntry->MarkEndOfOriginal();
        -                        push @{$groupEntry->GroupContent()}, $newGroup;
        -
        -                        $directoryGroups{$directory} = $newGroup;
        -                        $fileCount -= $count;
        -                        };
        -                    };
        -
        -
        -                # Now fill the subgroups.
        -
        -                if (scalar keys %directoryGroups)
        -                    {
        -                    my $afterOriginal;
        -                    my $index = 0;
        -
        -                    while ($index < scalar @{$groupEntry->GroupContent()})
        -                        {
        -                        my $entry = $groupEntry->GroupContent()->[$index];
        -
        -                        if ($entry->Type() == ::MENU_FILE())
        -                            {
        -                            my @entryDirectories =
        -                                NaturalDocs::File->SplitDirectories( (NaturalDocs::File->SplitPath($entry->Target()))[1] );
        -
        -                            my $unsharedDirectory = $entryDirectories[$unsharedIndex];
        -
        -                            if (exists $directoryGroups{$unsharedDirectory})
        -                                {
        -                                my $targetGroup = $directoryGroups{$unsharedDirectory};
        -
        -                                if ($afterOriginal)
        -                                    {  $targetGroup->MarkEndOfOriginal();  };
        -                                $targetGroup->PushToGroup($entry);
        -
        -                                $groupEntry->DeleteFromGroup($index);
        -                                }
        -                            else
        -                                {  $index++;  };
        -                            }
        -
        -                        elsif ($entry->Type() == ::MENU_ENDOFORIGINAL())
        -                            {
        -                            $afterOriginal = 1;
        -                            $index++;
        -                            }
        -
        -                        elsif ($entry->Type() == ::MENU_GROUP())
        -                            {
        -                            # See if we need to relocate this group.
        -
        -                            my @groupDirectories = $self->SharedDirectoriesOf($entry);
        -
        -                            # The group's shared directories must be at least two levels deeper than the current.  If the first level deeper
        -                            # is a new group, move it there because it's a subdirectory of that one.
        -                            if (scalar @groupDirectories - scalar @sharedDirectories >= 2)
        -                                {
        -                                my $unsharedDirectory = $groupDirectories[$unsharedIndex];
        -
        -                                if (exists $directoryGroups{$unsharedDirectory} &&
        -                                    $directoryGroups{$unsharedDirectory} != $entry)
        -                                    {
        -                                    my $targetGroup = $directoryGroups{$unsharedDirectory};
        -
        -                                    if ($afterOriginal)
        -                                        {  $targetGroup->MarkEndOfOriginal();  };
        -                                    $targetGroup->PushToGroup($entry);
        -
        -                                    $groupEntry->DeleteFromGroup($index);
        -
        -                                    # We need to retitle the group if it has the name of the unshared directory.
        -
        -                                    my $oldTitle = $entry->Title();
        -                                    $oldTitle =~ s/ +//g;
        -                                    $unsharedDirectory =~ s/ +//g;
        -
        -                                    if (lc($oldTitle) eq lc($unsharedDirectory))
        -                                        {
        -                                        $entry->SetTitle($groupDirectories[$unsharedIndex + 1]);
        -                                        };
        -                                    }
        -                                else
        -                                    {  $index++;  };
        -                                }
        -                            else
        -                                {  $index++;  };
        -                            }
        -
        -                        else
        -                            {  $index++;  };
        -                        };
        -
        -                    $hasChanged = 1;
        -
        -                    if ($fileCount <= MAXFILESINGROUP)
        -                        {  $groupEntry->SetFlags( $groupEntry->Flags() & ~::MENU_GROUP_UPDATESTRUCTURE() );  };
        -
        -                    $groupEntry->SetFlags( $groupEntry->Flags() | ::MENU_GROUP_UPDATETITLES() |
        -                                                                                         ::MENU_GROUP_UPDATEORDER() );
        -                    };
        -
        -                };  # If group has >MAXFILESINGROUP files
        -            };  # If group has UPDATESTRUCTURE
        -
        -
        -        # Okay, now go through all the subgroups.  We do this after the above so that newly created groups can get subgrouped
        -        # further.
        -
        -        foreach my $entry (@{$groupEntry->GroupContent()})
        -            {
        -            if ($entry->Type() == ::MENU_GROUP())
        -                {  push @groupStack, $entry;  };
        -            };
        -
        -        };  # For each group entry
        -    };
        -
        -
        -#
        -#   Function: DetectOrder
        -#
        -#   Detects the order of the entries in all groups that have the <MENU_GROUP_UPDATEORDER> flag set.  Will set one of the
        -#   <MENU_GROUP_FILESSORTED>, <MENU_GROUP_FILESANDGROUPSSORTED>, <MENU_GROUP_EVERYTHINGSORTED>, or
        -#   <MENU_GROUP_UNSORTED> flags.  It will always go for the most comprehensive sort possible, so if a group only has one
        -#   entry, it will be flagged as <MENU_GROUP_EVERYTHINGSORTED>.
        -#
        -#   <DetectIndexGroups()> should be called beforehand, as the <MENU_GROUP_ISINDEXGROUP> flag affects how the order is
        -#   detected.
        -#
        -#   The sort detection stops if it reaches a <MENU_ENDOFORIGINAL> entry, so new entries can be added to the end while still
        -#   allowing the original sort to be detected.
        -#
        -#   Parameters:
        -#
        -#       forceAll - If set, the order will be detected for all groups regardless of whether <MENU_GROUP_UPDATEORDER> is set.
        -#
        -sub DetectOrder #(forceAll)
        -    {
        -    my ($self, $forceAll) = @_;
        -    my @groupStack = ( $menu );
        -
        -    while (scalar @groupStack)
        -        {
        -        my $groupEntry = pop @groupStack;
        -        my $index = 0;
        -
        -
        -        # First detect the sort.
        -
        -        if ($forceAll || ($groupEntry->Flags() & ::MENU_GROUP_UPDATEORDER()) )
        -            {
        -            my $order = ::MENU_GROUP_EVERYTHINGSORTED();
        -
        -            my $lastFile;
        -            my $lastFileOrGroup;
        -
        -            while ($index < scalar @{$groupEntry->GroupContent()} &&
        -                     $groupEntry->GroupContent()->[$index]->Type() != ::MENU_ENDOFORIGINAL() &&
        -                     $order != ::MENU_GROUP_UNSORTED())
        -                {
        -                my $entry = $groupEntry->GroupContent()->[$index];
        -
        -
        -                # Ignore the last entry if it's an index group.  We don't want it to affect the sort.
        -
        -                if ($index + 1 == scalar @{$groupEntry->GroupContent()} &&
        -                    $entry->Type() == ::MENU_GROUP() && ($entry->Flags() & ::MENU_GROUP_ISINDEXGROUP()) )
        -                    {
        -                    # Ignore.
        -
        -                    # This is an awkward code construct, basically working towards an else instead of using an if, but the code just gets
        -                    # too hard to read otherwise.  The compiled code should work out to roughly the same thing anyway.
        -                    }
        -
        -
        -                # Ignore the first entry if it's the general index in an index group.  We don't want it to affect the sort.
        -
        -                elsif ($index == 0 && ($groupEntry->Flags() & ::MENU_GROUP_ISINDEXGROUP()) &&
        -                        $entry->Type() == ::MENU_INDEX() && $entry->Target() eq ::TOPIC_GENERAL() )
        -                    {
        -                    # Ignore.
        -                    }
        -
        -
        -                # Degenerate the sort.
        -
        -                else
        -                    {
        -
        -                    if ($order == ::MENU_GROUP_EVERYTHINGSORTED() && $index > 0 &&
        -                        ::StringCompare($entry->Title(), $groupEntry->GroupContent()->[$index - 1]->Title()) < 0)
        -                        {  $order = ::MENU_GROUP_FILESANDGROUPSSORTED();  };
        -
        -                    if ($order == ::MENU_GROUP_FILESANDGROUPSSORTED() &&
        -                        ($entry->Type() == ::MENU_FILE() || $entry->Type() == ::MENU_GROUP()) &&
        -                        defined $lastFileOrGroup && ::StringCompare($entry->Title(), $lastFileOrGroup->Title()) < 0)
        -                        {  $order = ::MENU_GROUP_FILESSORTED();  };
        -
        -                    if ($order == ::MENU_GROUP_FILESSORTED() &&
        -                        $entry->Type() == ::MENU_FILE() && defined $lastFile &&
        -                        ::StringCompare($entry->Title(), $lastFile->Title()) < 0)
        -                        {  $order = ::MENU_GROUP_UNSORTED();  };
        -
        -                    };
        -
        -
        -                # Set the lastX parameters for comparison and add sub-groups to the stack.
        -
        -                if ($entry->Type() == ::MENU_FILE())
        -                    {
        -                    $lastFile = $entry;
        -                    $lastFileOrGroup = $entry;
        -                    }
        -                elsif ($entry->Type() == ::MENU_GROUP())
        -                    {
        -                    $lastFileOrGroup = $entry;
        -                    push @groupStack, $entry;
        -                    };
        -
        -                $index++;
        -                };
        -
        -            $groupEntry->SetFlags($groupEntry->Flags() | $order);
        -            };
        -
        -
        -        # Find any subgroups in the remaining entries.
        -
        -        while ($index < scalar @{$groupEntry->GroupContent()})
        -            {
        -            my $entry = $groupEntry->GroupContent()->[$index];
        -
        -            if ($entry->Type() == ::MENU_GROUP())
        -                {  push @groupStack, $entry;  };
        -
        -            $index++;
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: GenerateAutoFileTitles
        -#
        -#   Creates titles for the unlocked file entries in all groups that have the <MENU_GROUP_UPDATETITLES> flag set.  It clears the
        -#   flag afterwards so it can be used efficiently for multiple sweeps.
        -#
        -#   Parameters:
        -#
        -#       forceAll - If set, forces all the unlocked file titles to update regardless of whether the group has the
        -#                     <MENU_GROUP_UPDATETITLES> flag set.
        -#
        -sub GenerateAutoFileTitles #(forceAll)
        -    {
        -    my ($self, $forceAll) = @_;
        -
        -    my @groupStack = ( $menu );
        -
        -    while (scalar @groupStack)
        -        {
        -        my $groupEntry = pop @groupStack;
        -
        -        if ($forceAll || ($groupEntry->Flags() & ::MENU_GROUP_UPDATETITLES()) )
        -            {
        -            # Find common prefixes and paths to strip from the default menu titles.
        -
        -            my @sharedDirectories = $self->SharedDirectoriesOf($groupEntry);
        -            my $noSharedDirectories = (scalar @sharedDirectories == 0);
        -
        -            my @sharedPrefixes;
        -            my $noSharedPrefixes;
        -
        -            foreach my $entry (@{$groupEntry->GroupContent()})
        -                {
        -                if ($entry->Type() == ::MENU_FILE())
        -                    {
        -                    # Find the common prefixes among all file entries that are unlocked and don't use the file name as their default title.
        -
        -                    my $defaultTitle = NaturalDocs::Project->DefaultMenuTitleOf($entry->Target());
        -
        -                    if (!$noSharedPrefixes && ($entry->Flags() & ::MENU_FILE_NOAUTOTITLE()) == 0 &&
        -                        $defaultTitle ne $entry->Target())
        -                        {
        -                        # If the filename is part of the title, separate it off so no part of it gets included as a common prefix.  This would
        -                        # happen if there's a group with only one file in it (Project.h => h) or only files that differ by extension
        -                        # (Project.h, Project.cpp => h, cpp) and people labeled them manually (// File: Project.h).
        -                        my $filename = (NaturalDocs::File->SplitPath($entry->Target()))[2];
        -                        my $filenamePart;
        -
        -                        if ( length $defaultTitle >= length $filename &&
        -                             lc(substr($defaultTitle, 0 - length($filename))) eq lc($filename) )
        -                            {
        -                            $filenamePart = substr($defaultTitle, 0 - length($filename));
        -                            $defaultTitle = substr($defaultTitle, 0, 0 - length($filename));
        -                            };
        -
        -
        -                        my @entryPrefixes = split(/(\.|::|->)/, $defaultTitle);
        -
        -                        # Remove potential leading undef/empty string.
        -                        if (!length $entryPrefixes[0])
        -                            {  shift @entryPrefixes;  };
        -
        -                        # Remove last entry.  Something has to exist for the title.  If we already separated off the filename, that will be
        -                        # it instead.
        -                        if (!$filenamePart)
        -                            {  pop @entryPrefixes;  };
        -
        -                        if (!scalar @entryPrefixes)
        -                            {  $noSharedPrefixes = 1;  }
        -                        elsif (!scalar @sharedPrefixes)
        -                            {  @sharedPrefixes = @entryPrefixes;  }
        -                        elsif ($entryPrefixes[0] ne $sharedPrefixes[0])
        -                            {  $noSharedPrefixes = 1;  }
        -
        -                        # If both arrays have entries, and the first is shared...
        -                        else
        -                            {
        -                            my $index = 1;
        -
        -                            while ($index < scalar @sharedPrefixes && $entryPrefixes[$index] eq $sharedPrefixes[$index])
        -                                {  $index++;  };
        -
        -                            if ($index < scalar @sharedPrefixes)
        -                                {  splice(@sharedPrefixes, $index);  };
        -                            };
        -                        };
        -
        -                    };  # if entry is MENU_FILE
        -                };  # foreach entry in group content.
        -
        -
        -            if (!scalar @sharedPrefixes)
        -                {  $noSharedPrefixes = 1;  };
        -
        -
        -            # Update all the menu titles of unlocked file entries.
        -
        -            foreach my $entry (@{$groupEntry->GroupContent()})
        -                {
        -                if ($entry->Type() == ::MENU_FILE() && ($entry->Flags() & ::MENU_FILE_NOAUTOTITLE()) == 0)
        -                    {
        -                    my $title = NaturalDocs::Project->DefaultMenuTitleOf($entry->Target());
        -
        -                    if ($title eq $entry->Target())
        -                        {
        -                        my ($volume, $directoryString, $file) = NaturalDocs::File->SplitPath($entry->Target());
        -                        my @directories = NaturalDocs::File->SplitDirectories($directoryString);
        -
        -                        if (!$noSharedDirectories)
        -                            {  splice(@directories, 0, scalar @sharedDirectories);  };
        -
        -                        # directory\...\directory\file.ext
        -
        -                        if (scalar @directories > 2)
        -                            {  @directories = ( $directories[0], '...', $directories[-1] );  };
        -
        -                        $directoryString = NaturalDocs::File->JoinDirectories(@directories);
        -                        $title = NaturalDocs::File->JoinPaths($directoryString, $file);
        -                        }
        -
        -                    else
        -                        {
        -                        my $filename = (NaturalDocs::File->SplitPath($entry->Target()))[2];
        -                        my $filenamePart;
        -
        -                        if ( length $title >= length $filename &&
        -                             lc(substr($title, 0 - length($filename))) eq lc($filename) )
        -                            {
        -                            $filenamePart = substr($title, 0 - length($filename));
        -                            $title = substr($title, 0, 0 - length($filename));
        -                            };
        -
        -                        my @segments = split(/(::|\.|->)/, $title);
        -                        if (!length $segments[0])
        -                            {  shift @segments;  };
        -
        -                        if ($filenamePart)
        -                            {  push @segments, $filenamePart;  };
        -
        -                        if (!$noSharedPrefixes)
        -                            {  splice(@segments, 0, scalar @sharedPrefixes);  };
        -
        -                        # package...package::target
        -
        -                        if (scalar @segments > 5)
        -                            {  splice(@segments, 1, scalar @segments - 4, '...');  };
        -
        -                        $title = join('', @segments);
        -                        };
        -
        -                    $entry->SetTitle($title);
        -                    };  # If entry is an unlocked file
        -                };  # Foreach entry
        -
        -            $groupEntry->SetFlags( $groupEntry->Flags() & ~::MENU_GROUP_UPDATETITLES() );
        -
        -            };  # If updating group titles
        -
        -        # Now find any subgroups.
        -        foreach my $entry (@{$groupEntry->GroupContent()})
        -            {
        -            if ($entry->Type() == ::MENU_GROUP())
        -                {  push @groupStack, $entry;  };
        -            };
        -        };
        -
        -    };
        -
        -
        -#
        -#   Function: ResortGroups
        -#
        -#   Resorts all groups that have <MENU_GROUP_UPDATEORDER> set.  Assumes <DetectOrder()> and <GenerateAutoFileTitles()>
        -#   have already been called.  Will clear the flag and any <MENU_ENDOFORIGINAL> entries on reordered groups.
        -#
        -#   Parameters:
        -#
        -#       forceAll - If set, resorts all groups regardless of whether <MENU_GROUP_UPDATEORDER> is set.
        -#
        -sub ResortGroups #(forceAll)
        -    {
        -    my ($self, $forceAll) = @_;
        -    my @groupStack = ( $menu );
        -
        -    while (scalar @groupStack)
        -        {
        -        my $groupEntry = pop @groupStack;
        -
        -        if ($forceAll || ($groupEntry->Flags() & ::MENU_GROUP_UPDATEORDER()) )
        -            {
        -            my $newEntriesIndex;
        -
        -
        -            # Strip the ENDOFORIGINAL.
        -
        -            if ($groupEntry->Flags() & ::MENU_GROUP_HASENDOFORIGINAL())
        -                {
        -                $newEntriesIndex = 0;
        -
        -                while ($newEntriesIndex < scalar @{$groupEntry->GroupContent()} &&
        -                         $groupEntry->GroupContent()->[$newEntriesIndex]->Type() != ::MENU_ENDOFORIGINAL() )
        -                    {  $newEntriesIndex++;  };
        -
        -                $groupEntry->DeleteFromGroup($newEntriesIndex);
        -
        -                $groupEntry->SetFlags( $groupEntry->Flags() & ~::MENU_GROUP_HASENDOFORIGINAL() );
        -                }
        -            else
        -                {  $newEntriesIndex = -1;  };
        -
        -
        -            # Strip the exceptions.
        -
        -            my $trailingIndexGroup;
        -            my $leadingGeneralIndex;
        -
        -            if ( ($groupEntry->Flags() & ::MENU_GROUP_ISINDEXGROUP()) &&
        -                 $groupEntry->GroupContent()->[0]->Type() == ::MENU_INDEX() &&
        -                 $groupEntry->GroupContent()->[0]->Target() eq ::TOPIC_GENERAL() )
        -                {
        -                $leadingGeneralIndex = shift @{$groupEntry->GroupContent()};
        -                if ($newEntriesIndex != -1)
        -                    {  $newEntriesIndex--;  };
        -                }
        -
        -            elsif (scalar @{$groupEntry->GroupContent()} && $newEntriesIndex != 0)
        -                {
        -                my $lastIndex;
        -
        -                if ($newEntriesIndex != -1)
        -                    {  $lastIndex = $newEntriesIndex - 1;  }
        -                else
        -                    {  $lastIndex = scalar @{$groupEntry->GroupContent()} - 1;  };
        -
        -                if ($groupEntry->GroupContent()->[$lastIndex]->Type() == ::MENU_GROUP() &&
        -                    ( $groupEntry->GroupContent()->[$lastIndex]->Flags() & ::MENU_GROUP_ISINDEXGROUP() ) )
        -                    {
        -                    $trailingIndexGroup = $groupEntry->GroupContent()->[$lastIndex];
        -                    $groupEntry->DeleteFromGroup($lastIndex);
        -
        -                    if ($newEntriesIndex != -1)
        -                        {  $newEntriesIndex++;  };
        -                    };
        -                };
        -
        -
        -            # If there weren't already exceptions, strip them from the new entries.
        -
        -            if ( (!defined $trailingIndexGroup || !defined $leadingGeneralIndex) && $newEntriesIndex != -1)
        -                {
        -                my $index = $newEntriesIndex;
        -
        -                while ($index < scalar @{$groupEntry->GroupContent()})
        -                    {
        -                    my $entry = $groupEntry->GroupContent()->[$index];
        -
        -                    if (!defined $trailingIndexGroup &&
        -                        $entry->Type() == ::MENU_GROUP() && ($entry->Flags() & ::MENU_GROUP_ISINDEXGROUP()) )
        -                        {
        -                        $trailingIndexGroup = $entry;
        -                        $groupEntry->DeleteFromGroup($index);
        -                        }
        -                    elsif (!defined $leadingGeneralIndex && ($groupEntry->Flags() & ::MENU_GROUP_ISINDEXGROUP()) &&
        -                            $entry->Type() == ::MENU_INDEX() && !defined $entry->Target())
        -                        {
        -                        $leadingGeneralIndex = $entry;
        -                        $groupEntry->DeleteFromGroup($index);
        -                        }
        -                    else
        -                        {  $index++;  };
        -                    };
        -                };
        -
        -
        -            # If there's no order, we still want to sort the new additions.
        -
        -            if ($groupEntry->Flags() & ::MENU_GROUP_UNSORTED())
        -                {
        -                if ($newEntriesIndex != -1)
        -                    {
        -                    my @newEntries =
        -                        @{$groupEntry->GroupContent()}[$newEntriesIndex..scalar @{$groupEntry->GroupContent()} - 1];
        -
        -                    @newEntries = sort { $self->CompareEntries($a, $b) } @newEntries;
        -
        -                    foreach my $newEntry (@newEntries)
        -                        {
        -                        $groupEntry->GroupContent()->[$newEntriesIndex] = $newEntry;
        -                        $newEntriesIndex++;
        -                        };
        -                    };
        -                }
        -
        -            elsif ($groupEntry->Flags() & ::MENU_GROUP_EVERYTHINGSORTED())
        -                {
        -                @{$groupEntry->GroupContent()} = sort { $self->CompareEntries($a, $b) } @{$groupEntry->GroupContent()};
        -                }
        -
        -            elsif ( ($groupEntry->Flags() & ::MENU_GROUP_FILESSORTED()) ||
        -                     ($groupEntry->Flags() & ::MENU_GROUP_FILESANDGROUPSSORTED()) )
        -                {
        -                my $groupContent = $groupEntry->GroupContent();
        -                my @newEntries;
        -
        -                if ($newEntriesIndex != -1)
        -                    {  @newEntries = splice( @$groupContent, $newEntriesIndex );  };
        -
        -
        -                # First resort the existing entries.
        -
        -                # A couple of support functions.  They're defined here instead of spun off into their own functions because they're only
        -                # used here and to make them general we would need to add support for the other sort options.
        -
        -                sub IsIncludedInSort #(groupEntry, entry)
        -                    {
        -                    my ($self, $groupEntry, $entry) = @_;
        -
        -                    return ($entry->Type() == ::MENU_FILE() ||
        -                                ( $entry->Type() == ::MENU_GROUP() &&
        -                                    ($groupEntry->Flags() & ::MENU_GROUP_FILESANDGROUPSSORTED()) ) );
        -                    };
        -
        -                sub IsSorted #(groupEntry)
        -                    {
        -                    my ($self, $groupEntry) = @_;
        -                    my $lastApplicable;
        -
        -                    foreach my $entry (@{$groupEntry->GroupContent()})
        -                        {
        -                        # If the entry is applicable to the sort order...
        -                        if ($self->IsIncludedInSort($groupEntry, $entry))
        -                            {
        -                            if (defined $lastApplicable)
        -                                {
        -                                if ($self->CompareEntries($entry, $lastApplicable) < 0)
        -                                    {  return undef;  };
        -                                };
        -
        -                            $lastApplicable = $entry;
        -                            };
        -                        };
        -
        -                    return 1;
        -                    };
        -
        -
        -                # There's a good chance it's still sorted.  They should only become unsorted if an auto-title changes.
        -                if (!$self->IsSorted($groupEntry))
        -                    {
        -                    # Crap.  Okay, method one is to sort each group of continuous sortable elements.  There's a possibility that doing
        -                    # this will cause the whole to become sorted again.  We try this first, even though it isn't guaranteed to succeed,
        -                    # because it will restore the sort without moving any unsortable entries.
        -
        -                    # Copy it because we'll need the original if this fails.
        -                    my @originalGroupContent = @$groupContent;
        -
        -                    my $index = 0;
        -                    my $startSortable = 0;
        -
        -                    while (1)
        -                        {
        -                        # If index is on an unsortable entry or the end of the array...
        -                        if ($index == scalar @$groupContent || !$self->IsIncludedInSort($groupEntry, $groupContent->[$index]))
        -                            {
        -                            # If we have at least two sortable entries...
        -                            if ($index - $startSortable >= 2)
        -                                {
        -                                # Sort them.
        -                                my @sortableEntries = @{$groupContent}[$startSortable .. $index - 1];
        -                                @sortableEntries = sort { $self->CompareEntries($a, $b) } @sortableEntries;
        -                                foreach my $sortableEntry (@sortableEntries)
        -                                    {
        -                                    $groupContent->[$startSortable] = $sortableEntry;
        -                                    $startSortable++;
        -                                    };
        -                                };
        -
        -                            if ($index == scalar @$groupContent)
        -                                {  last;  };
        -
        -                            $startSortable = $index + 1;
        -                            };
        -
        -                        $index++;
        -                        };
        -
        -                    if (!$self->IsSorted($groupEntry))
        -                        {
        -                        # Crap crap.  Okay, now we do a full sort but with potential damage to the original structure.  Each unsortable
        -                        # element is locked to the next sortable element.  We sort the sortable elements, bringing all the unsortable
        -                        # pieces with them.
        -
        -                        my @pieces = ( [ ] );
        -                        my $currentPiece = $pieces[0];
        -
        -                        foreach my $entry (@originalGroupContent)
        -                            {
        -                            push @$currentPiece, $entry;
        -
        -                            # If the entry is sortable...
        -                            if ($self->IsIncludedInSort($groupEntry, $entry))
        -                                {
        -                                $currentPiece = [ ];
        -                                push @pieces, $currentPiece;
        -                                };
        -                            };
        -
        -                        my $lastUnsortablePiece;
        -
        -                        # If the last entry was sortable, we'll have an empty piece at the end.  Drop it.
        -                        if (scalar @{$pieces[-1]} == 0)
        -                            {  pop @pieces;  }
        -
        -                        # If the last entry wasn't sortable, the last piece won't end with a sortable element.  Save it, but remove it
        -                        # from the list.
        -                        else
        -                            {  $lastUnsortablePiece = pop @pieces;  };
        -
        -                        # Sort the list.
        -                        @pieces = sort { $self->CompareEntries( $a->[-1], $b->[-1] ) } @pieces;
        -
        -                        # Copy it back to the original.
        -                        if (defined $lastUnsortablePiece)
        -                            {  push @pieces, $lastUnsortablePiece;  };
        -
        -                        my $index = 0;
        -
        -                        foreach my $piece (@pieces)
        -                            {
        -                            foreach my $entry (@{$piece})
        -                                {
        -                                $groupEntry->GroupContent()->[$index] = $entry;
        -                                $index++;
        -                                };
        -                            };
        -                        };
        -                    };
        -
        -
        -                # Okay, the orginal entries are sorted now.  Sort the new entries and apply.
        -
        -                if (scalar @newEntries)
        -                    {
        -                    @newEntries = sort { $self->CompareEntries($a, $b) } @newEntries;
        -                    my @originalEntries = @$groupContent;
        -                    @$groupContent = ( );
        -
        -                    while (1)
        -                        {
        -                        while (scalar @originalEntries && !$self->IsIncludedInSort($groupEntry, $originalEntries[0]))
        -                            {  push @$groupContent, (shift @originalEntries);  };
        -
        -                        if (!scalar @originalEntries || !scalar @newEntries)
        -                            {  last;  };
        -
        -                        while (scalar @newEntries && $self->CompareEntries($newEntries[0], $originalEntries[0]) < 0)
        -                            {  push @$groupContent, (shift @newEntries);  };
        -
        -                        push @$groupContent, (shift @originalEntries);
        -
        -                        if (!scalar @originalEntries || !scalar @newEntries)
        -                            {  last;  };
        -                        };
        -
        -                    if (scalar @originalEntries)
        -                        {  push @$groupContent, @originalEntries;  }
        -                    elsif (scalar @newEntries)
        -                        {  push @$groupContent, @newEntries;  };
        -                    };
        -                };
        -
        -
        -            # Now re-add the exceptions.
        -
        -            if (defined $leadingGeneralIndex)
        -                {
        -                unshift @{$groupEntry->GroupContent()}, $leadingGeneralIndex;
        -                };
        -
        -            if (defined $trailingIndexGroup)
        -                {
        -                $groupEntry->PushToGroup($trailingIndexGroup);
        -                };
        -
        -            };
        -
        -        foreach my $entry (@{$groupEntry->GroupContent()})
        -            {
        -            if ($entry->Type() == ::MENU_GROUP())
        -                {  push @groupStack, $entry;  };
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: CompareEntries
        -#
        -#   A comparison function for use in sorting.  Compares the two entries by their titles with <StringCompare()>, but in the case
        -#   of a tie, puts <MENU_FILE> entries above <MENU_GROUP> entries.
        -#
        -sub CompareEntries #(a, b)
        -    {
        -    my ($self, $a, $b) = @_;
        -
        -    my $result = ::StringCompare($a->Title(), $b->Title());
        -
        -    if ($result == 0)
        -        {
        -        if ($a->Type() == ::MENU_FILE() && $b->Type() == ::MENU_GROUP())
        -            {  $result = -1;  }
        -        elsif ($a->Type() == ::MENU_GROUP() && $b->Type() == ::MENU_FILE())
        -            {  $result = 1;  };
        -        };
        -
        -    return $result;
        -    };
        -
        -
        -#
        -#   Function: SharedDirectoriesOf
        -#
        -#   Returns an array of all the directories shared by the files in the group.  If none, returns an empty array.
        -#
        -sub SharedDirectoriesOf #(group)
        -    {
        -    my ($self, $groupEntry) = @_;
        -    my @sharedDirectories;
        -
        -    foreach my $entry (@{$groupEntry->GroupContent()})
        -        {
        -        if ($entry->Type() == ::MENU_FILE())
        -            {
        -            my @entryDirectories = NaturalDocs::File->SplitDirectories( (NaturalDocs::File->SplitPath($entry->Target()))[1] );
        -
        -            if (!scalar @sharedDirectories)
        -                {  @sharedDirectories = @entryDirectories;  }
        -            else
        -                {  ::ShortenToMatchStrings(\@sharedDirectories, \@entryDirectories);  };
        -
        -            if (!scalar @sharedDirectories)
        -                {  last;  };
        -            };
        -        };
        -
        -    return @sharedDirectories;
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Menu/Entry.pm b/vendor/naturaldocs/Modules/NaturalDocs/Menu/Entry.pm
        deleted file mode 100644
        index 00bdd4e29..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Menu/Entry.pm
        +++ /dev/null
        @@ -1,202 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Menu::Entry
        -#
        -###############################################################################
        -#
        -#   A class representing an entry in the menu.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Menu::Entry;
        -
        -
        -###############################################################################
        -# Group: Implementation
        -
        -#
        -#   Constants: Members
        -#
        -#   The object is implemented as a blessed arrayref with the indexes below.
        -#
        -#       TYPE      - The <MenuEntryType>
        -#       TITLE     - The title of the entry.
        -#       TARGET  - The target of the entry.  If the type is <MENU_FILE>, it will be the source <FileName>.  If the type is
        -#                       <MENU_LINK>, it will be the URL.  If the type is <MENU_GROUP>, it will be an arrayref of
        -#                       <NaturalDocs::Menu::Entry> objects representing the group's content.  If the type is <MENU_INDEX>, it will be
        -#                       a <TopicType>.
        -#       FLAGS    - Any <Menu Entry Flags> that apply.
        -#
        -use constant TYPE => 0;
        -use constant TITLE => 1;
        -use constant TARGET => 2;
        -use constant FLAGS => 3;
        -# DEPENDENCY: New() depends on the order of these constants.
        -
        -
        -###############################################################################
        -# Group: Functions
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -#   Parameters:
        -#
        -#       type     - The <MenuEntryType>.
        -#       title      - The title of the entry.
        -#       target   - The target of the entry, if applicable.  If the type is <MENU_FILE>, use the source <FileName>.  If the type is
        -#                     <MENU_LINK>, use the URL.  If the type is <MENU_INDEX>, use the <TopicType>.  Otherwise set it to undef.
        -#       flags     - Any <Menu Entry Flags> that apply.
        -#
        -sub New #(type, title, target, flags)
        -    {
        -    # DEPENDENCY: This gode depends on the order of the constants.
        -
        -    my $package = shift;
        -
        -    my $object = [ @_ ];
        -    bless $object, $package;
        -
        -    if ($object->[TYPE] == ::MENU_GROUP())
        -        {  $object->[TARGET] = [ ];  };
        -    if (!defined $object->[FLAGS])
        -        {  $object->[FLAGS] = 0;  };
        -
        -    return $object;
        -    };
        -
        -
        -#   Function: Type
        -#   Returns the <MenuEntryType>.
        -sub Type
        -    {  return $_[0]->[TYPE];  };
        -
        -#   Function: Title
        -#   Returns the title of the entry.
        -sub Title
        -    {  return $_[0]->[TITLE];  };
        -
        -# Function: SetTitle
        -# Replaces the entry's title.
        -sub SetTitle #(title)
        -    {  $_[0]->[TITLE] = $_[1];  };
        -
        -#
        -#   Function: Target
        -#
        -#   Returns the target of the entry, if applicable.  If the type is <MENU_FILE>, it returns the source <FileName>.  If the type is
        -#   <MENU_LINK>, it returns the URL.  If the type is <MENU_INDEX>, it returns the <TopicType>.  Otherwise it returns undef.
        -#
        -sub Target
        -    {
        -    my $self = shift;
        -
        -    # Group entries are the only time when target won't be undef when it should be.
        -    if ($self->Type() == ::MENU_GROUP())
        -        {  return undef;  }
        -    else
        -        {  return $self->[TARGET];  };
        -    };
        -
        -# Function: SetTarget
        -# Replaces the entry's target.
        -sub SetTarget #(target)
        -    {  $_[0]->[TARGET] = $_[1];  };
        -
        -#   Function: Flags
        -#   Returns the <Menu Entry Flags>.
        -sub Flags
        -    {  return $_[0]->[FLAGS];  };
        -
        -# Function: SetFlags
        -# Replaces the <Menu Entry Flags>.
        -sub SetFlags #(flags)
        -    {  $_[0]->[FLAGS] = $_[1];  };
        -
        -
        -
        -###############################################################################
        -# Group: Group Functions
        -#
        -#   All of these functions assume the type is <MENU_GROUP>.  Do *not* call any of these without checking <Type()> first.
        -
        -
        -#
        -#   Function: GroupContent
        -#
        -#   Returns an arrayref of <NaturalDocs::Menu::Entry> objects representing the contents of the
        -#   group, or undef otherwise.  This arrayref will always exist for <MENU_GROUP>'s and can be changed.
        -#
        -sub GroupContent
        -    {
        -    return $_[0]->[TARGET];
        -    };
        -
        -
        -#
        -#   Function: GroupIsEmpty
        -#
        -#   If the type is <MENU_GROUP>, returns whether the group is empty.
        -#
        -sub GroupIsEmpty
        -    {
        -    my $self = shift;
        -    return (scalar @{$self->GroupContent()} > 0);
        -    };
        -
        -
        -#
        -#   Function: PushToGroup
        -#
        -#   Pushes the entry to the end of the group content.
        -#
        -sub PushToGroup #(entry)
        -    {
        -    my ($self, $entry) = @_;
        -    push @{$self->GroupContent()}, $entry;
        -    };
        -
        -
        -#
        -#   Function: DeleteFromGroup
        -#
        -#   Deletes an entry from the group content by index.
        -#
        -sub DeleteFromGroup #(index)
        -    {
        -    my ($self, $index) = @_;
        -
        -    my $groupContent = $self->GroupContent();
        -
        -    splice( @$groupContent, $index, 1 );
        -    };
        -
        -
        -#
        -#   Function: MarkEndOfOriginal
        -#
        -#   If the group doesn't already have one, adds a <MENU_ENDOFORIGINAL> entry to the end and sets the
        -#   <MENU_GROUP_HASENDOFORIGINAL> flag.
        -#
        -sub MarkEndOfOriginal
        -    {
        -    my $self = shift;
        -
        -    if (($self->Flags() & ::MENU_GROUP_HASENDOFORIGINAL()) == 0)
        -        {
        -        $self->PushToGroup( NaturalDocs::Menu::Entry->New(::MENU_ENDOFORIGINAL(), undef, undef, undef) );
        -        $self->SetFlags( $self->Flags() | ::MENU_GROUP_HASENDOFORIGINAL() );
        -        };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/NDMarkup.pm b/vendor/naturaldocs/Modules/NaturalDocs/NDMarkup.pm
        deleted file mode 100644
        index 46adc0211..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/NDMarkup.pm
        +++ /dev/null
        @@ -1,77 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::NDMarkup
        -#
        -###############################################################################
        -#
        -#   A package of support functions for dealing with <NDMarkup>.
        -#
        -#   Usage and Dependencies:
        -#
        -#       The package doesn't depend on any Natural Docs packages and is ready to use right away.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::NDMarkup;
        -
        -#
        -#   Function: ConvertAmpChars
        -#
        -#   Substitutes certain characters with their <NDMarkup> amp chars.
        -#
        -#   Parameters:
        -#
        -#       text - The block of text to convert.
        -#
        -#   Returns:
        -#
        -#       The converted text block.
        -#
        -sub ConvertAmpChars #(text)
        -    {
        -    my ($self, $text) = @_;
        -
        -    $text =~ s/&/&amp;/g;
        -    $text =~ s/</&lt;/g;
        -    $text =~ s/>/&gt;/g;
        -    $text =~ s/\"/&quot;/g;
        -
        -    return $text;
        -    };
        -
        -
        -#
        -#   Function: RestoreAmpChars
        -#
        -#   Replaces <NDMarkup> amp chars with their original symbols.
        -#
        -#   Parameters:
        -#
        -#       text - The text to restore.
        -#
        -#   Returns:
        -#
        -#       The restored text.
        -#
        -sub RestoreAmpChars #(text)
        -    {
        -    my ($self, $text) = @_;
        -
        -    $text =~ s/&quot;/\"/g;
        -    $text =~ s/&gt;/>/g;
        -    $text =~ s/&lt;/</g;
        -    $text =~ s/&amp;/&/g;
        -
        -    return $text;
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Parser.pm b/vendor/naturaldocs/Modules/NaturalDocs/Parser.pm
        deleted file mode 100644
        index 24c415feb..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Parser.pm
        +++ /dev/null
        @@ -1,1335 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Parser
        -#
        -###############################################################################
        -#
        -#   A package that coordinates source file parsing between the <NaturalDocs::Languages::Base>-derived objects and its own
        -#   sub-packages such as <NaturalDocs::Parser::Native>.  Also handles sending symbols to <NaturalDocs::SymbolTable> and
        -#   other generic topic processing.
        -#
        -#   Usage and Dependencies:
        -#
        -#       - Prior to use, <NaturalDocs::Settings>, <NaturalDocs::Languages>, <NaturalDocs::Project>, <NaturalDocs::SymbolTable>,
        -#         and <NaturalDocs::ClassHierarchy> must be initialized.  <NaturalDocs::SymbolTable> and <NaturalDocs::ClassHierarchy>
        -#         do not have to be fully resolved.
        -#
        -#       - Aside from that, the package is ready to use right away.  It does not have its own initialization function.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use NaturalDocs::Parser::ParsedTopic;
        -use NaturalDocs::Parser::Native;
        -use NaturalDocs::Parser::JavaDoc;
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Parser;
        -
        -
        -
        -###############################################################################
        -# Group: Variables
        -
        -
        -#
        -#   var: sourceFile
        -#
        -#   The source <FileName> currently being parsed.
        -#
        -my $sourceFile;
        -
        -#
        -#   var: language
        -#
        -#   The language object for the file, derived from <NaturalDocs::Languages::Base>.
        -#
        -my $language;
        -
        -#
        -#   Array: parsedFile
        -#
        -#   An array of <NaturalDocs::Parser::ParsedTopic> objects.
        -#
        -my @parsedFile;
        -
        -
        -#
        -#   bool: parsingForInformation
        -#   Whether <ParseForInformation()> was called.  If false, then <ParseForBuild()> was called.
        -#
        -my $parsingForInformation;
        -
        -
        -
        -###############################################################################
        -# Group: Functions
        -
        -#
        -#   Function: ParseForInformation
        -#
        -#   Parses the input file for information.  Will update the information about the file in <NaturalDocs::SymbolTable> and
        -#   <NaturalDocs::Project>.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName> to parse.
        -#
        -sub ParseForInformation #(file)
        -    {
        -    my ($self, $file) = @_;
        -    $sourceFile = $file;
        -
        -    $parsingForInformation = 1;
        -
        -    # Watch this parse so we detect any changes.
        -    NaturalDocs::SymbolTable->WatchFileForChanges($sourceFile);
        -    NaturalDocs::ClassHierarchy->WatchFileForChanges($sourceFile);
        -    NaturalDocs::SourceDB->WatchFileForChanges($sourceFile);
        -
        -    my $defaultMenuTitle = $self->Parse();
        -
        -    foreach my $topic (@parsedFile)
        -        {
        -        # Add a symbol for the topic.
        -
        -        my $type = $topic->Type();
        -        if ($type eq ::TOPIC_ENUMERATION())
        -            {  $type = ::TOPIC_TYPE();  };
        -
        -        NaturalDocs::SymbolTable->AddSymbol($topic->Symbol(), $sourceFile, $type,
        -                                                                   $topic->Prototype(), $topic->Summary());
        -
        -
        -        # You can't put the function call directly in a while with a regex.  It has to sit in a variable to work.
        -        my $body = $topic->Body();
        -
        -
        -        # If it's a list or enum topic, add a symbol for each description list entry.
        -
        -        if ($topic->IsList() || $topic->Type() eq ::TOPIC_ENUMERATION())
        -            {
        -            # We'll hijack the enum constants to apply to non-enum behavior too.
        -            my $behavior;
        -
        -            if ($topic->Type() eq ::TOPIC_ENUMERATION())
        -                {
        -                $type = ::TOPIC_CONSTANT();
        -                $behavior = $language->EnumValues();
        -                }
        -            elsif (NaturalDocs::Topics->TypeInfo($topic->Type())->Scope() == ::SCOPE_ALWAYS_GLOBAL())
        -                {
        -                $behavior = ::ENUM_GLOBAL();
        -                }
        -            else
        -                {
        -                $behavior = ::ENUM_UNDER_PARENT();
        -                };
        -
        -            while ($body =~ /<ds>([^<]+)<\/ds><dd>(.*?)<\/dd>/g)
        -                {
        -                my ($listTextSymbol, $listSummary) = ($1, $2);
        -
        -                $listTextSymbol = NaturalDocs::NDMarkup->RestoreAmpChars($listTextSymbol);
        -                my $listSymbol = NaturalDocs::SymbolString->FromText($listTextSymbol);
        -
        -                if ($behavior == ::ENUM_UNDER_PARENT())
        -                    {  $listSymbol = NaturalDocs::SymbolString->Join($topic->Package(), $listSymbol);  }
        -                elsif ($behavior == ::ENUM_UNDER_TYPE())
        -                    {  $listSymbol = NaturalDocs::SymbolString->Join($topic->Symbol(), $listSymbol);  };
        -
        -                NaturalDocs::SymbolTable->AddSymbol($listSymbol, $sourceFile, $type, undef,
        -                                                                           $self->GetSummaryFromDescriptionList($listSummary));
        -                };
        -            };
        -
        -
        -        # Add references in the topic.
        -
        -        while ($body =~ /<link target=\"([^\"]*)\" name=\"[^\"]*\" original=\"[^\"]*\">/g)
        -            {
        -            my $linkText = NaturalDocs::NDMarkup->RestoreAmpChars($1);
        -            my $linkSymbol = NaturalDocs::SymbolString->FromText($linkText);
        -
        -            NaturalDocs::SymbolTable->AddReference(::REFERENCE_TEXT(), $linkSymbol,
        -                                                                           $topic->Package(), $topic->Using(), $sourceFile);
        -            };
        -
        -
        -        # Add images in the topic.
        -
        -        while ($body =~ /<img mode=\"[^\"]*\" target=\"([^\"]+)\" original=\"[^\"]*\">/g)
        -            {
        -            my $target = NaturalDocs::NDMarkup->RestoreAmpChars($1);
        -            NaturalDocs::ImageReferenceTable->AddReference($sourceFile, $target);
        -            };
        -        };
        -
        -    # Handle any changes to the file.
        -    NaturalDocs::ClassHierarchy->AnalyzeChanges();
        -    NaturalDocs::SymbolTable->AnalyzeChanges();
        -    NaturalDocs::SourceDB->AnalyzeWatchedFileChanges();
        -
        -    # Update project on the file's characteristics.
        -    my $hasContent = (scalar @parsedFile > 0);
        -
        -    NaturalDocs::Project->SetHasContent($sourceFile, $hasContent);
        -    if ($hasContent)
        -        {  NaturalDocs::Project->SetDefaultMenuTitle($sourceFile, $defaultMenuTitle);  };
        -
        -    # We don't need to keep this around.
        -    @parsedFile = ( );
        -    };
        -
        -
        -#
        -#   Function: ParseForBuild
        -#
        -#   Parses the input file for building, returning it as a <NaturalDocs::Parser::ParsedTopic> arrayref.
        -#
        -#   Note that all new and changed files should be parsed for symbols via <ParseForInformation()> before calling this function on
        -#   *any* file.  The reason is that <NaturalDocs::SymbolTable> needs to know about all the symbol definitions and references to
        -#   resolve them properly.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName> to parse for building.
        -#
        -#   Returns:
        -#
        -#       An arrayref of the source file as <NaturalDocs::Parser::ParsedTopic> objects.
        -#
        -sub ParseForBuild #(file)
        -    {
        -    my ($self, $file) = @_;
        -    $sourceFile = $file;
        -
        -    $parsingForInformation = undef;
        -
        -    $self->Parse();
        -
        -    return \@parsedFile;
        -    };
        -
        -
        -
        -
        -###############################################################################
        -# Group: Interface Functions
        -
        -
        -#
        -#   Function: OnComment
        -#
        -#   The function called by <NaturalDocs::Languages::Base>-derived objects when their parsers encounter a comment
        -#   suitable for documentation.
        -#
        -#   Parameters:
        -#
        -#       commentLines - An arrayref of the comment's lines.  The language's comment symbols should be converted to spaces,
        -#                               and there should be no line break characters at the end of each line.  *The original memory will be
        -#                               changed.*
        -#       lineNumber - The line number of the first of the comment lines.
        -#       isJavaDoc - Whether the comment is in JavaDoc format.
        -#
        -#   Returns:
        -#
        -#       The number of topics created by this comment, or zero if none.
        -#
        -sub OnComment #(string[] commentLines, int lineNumber, bool isJavaDoc)
        -    {
        -    my ($self, $commentLines, $lineNumber, $isJavaDoc) = @_;
        -
        -    $self->CleanComment($commentLines);
        -
        -    # We check if it's definitely Natural Docs content first.  This overrides all else, since it's possible that a comment could start
        -    # with a topic line yet have something that looks like a JavaDoc tag.  Natural Docs wins in this case.
        -    if (NaturalDocs::Parser::Native->IsMine($commentLines, $isJavaDoc))
        -        {  return NaturalDocs::Parser::Native->ParseComment($commentLines, $isJavaDoc, $lineNumber, \@parsedFile);  }
        -
        -    elsif (NaturalDocs::Parser::JavaDoc->IsMine($commentLines, $isJavaDoc))
        -        {  return NaturalDocs::Parser::JavaDoc->ParseComment($commentLines, $isJavaDoc, $lineNumber, \@parsedFile);  }
        -
        -    # If the content is ambiguous and it's a JavaDoc-styled comment, treat it as Natural Docs content.
        -    elsif ($isJavaDoc)
        -        {  return NaturalDocs::Parser::Native->ParseComment($commentLines, $isJavaDoc, $lineNumber, \@parsedFile);  }
        -    };
        -
        -
        -#
        -#   Function: OnClass
        -#
        -#   A function called by <NaturalDocs::Languages::Base>-derived objects when their parsers encounter a class declaration.
        -#
        -#   Parameters:
        -#
        -#       class - The <SymbolString> of the class encountered.
        -#
        -sub OnClass #(class)
        -    {
        -    my ($self, $class) = @_;
        -
        -    if ($parsingForInformation)
        -        {  NaturalDocs::ClassHierarchy->AddClass($sourceFile, $class);  };
        -    };
        -
        -
        -#
        -#   Function: OnClassParent
        -#
        -#   A function called by <NaturalDocs::Languages::Base>-derived objects when their parsers encounter a declaration of
        -#   inheritance.
        -#
        -#   Parameters:
        -#
        -#       class - The <SymbolString> of the class we're in.
        -#       parent - The <SymbolString> of the class it inherits.
        -#       scope - The package <SymbolString> that the reference appeared in.
        -#       using - An arrayref of package <SymbolStrings> that the reference has access to via "using" statements.
        -#       resolvingFlags - Any <Resolving Flags> to be used when resolving the reference.  <RESOLVE_NOPLURAL> is added
        -#                              automatically since that would never apply to source code.
        -#
        -sub OnClassParent #(class, parent, scope, using, resolvingFlags)
        -    {
        -    my ($self, $class, $parent, $scope, $using, $resolvingFlags) = @_;
        -
        -    if ($parsingForInformation)
        -        {
        -        NaturalDocs::ClassHierarchy->AddParentReference($sourceFile, $class, $parent, $scope, $using,
        -                                                                                   $resolvingFlags | ::RESOLVE_NOPLURAL());
        -        };
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -
        -#   Function: Parse
        -#
        -#   Opens the source file and parses process.  Most of the actual parsing is done in <NaturalDocs::Languages::Base->ParseFile()>
        -#   and <OnComment()>, though.
        -#
        -#   *Do not call externally.*  Rather, call <ParseForInformation()> or <ParseForBuild()>.
        -#
        -#   Returns:
        -#
        -#       The default menu title of the file.  Will be the <FileName> if nothing better is found.
        -#
        -sub Parse
        -    {
        -    my ($self) = @_;
        -
        -    NaturalDocs::Error->OnStartParsing($sourceFile);
        -
        -    $language = NaturalDocs::Languages->LanguageOf($sourceFile);
        -    NaturalDocs::Parser::Native->Start();
        -    @parsedFile = ( );
        -
        -    my ($autoTopics, $scopeRecord) = $language->ParseFile($sourceFile, \@parsedFile);
        -
        -
        -    $self->AddToClassHierarchy();
        -
        -    $self->BreakLists();
        -
        -    if (defined $autoTopics)
        -        {
        -        if (defined $scopeRecord)
        -            {  $self->RepairPackages($autoTopics, $scopeRecord);  };
        -
        -        $self->MergeAutoTopics($language, $autoTopics);
        -        };
        -
        -    $self->RemoveRemainingHeaderlessTopics();
        -
        -
        -    # We don't need to do this if there aren't any auto-topics because the only package changes would be implied by the comments.
        -    if (defined $autoTopics)
        -        {  $self->AddPackageDelineators();  };
        -
        -    if (!NaturalDocs::Settings->NoAutoGroup())
        -        {  $self->MakeAutoGroups($autoTopics);  };
        -
        -
        -    # Set the menu title.
        -
        -    my $defaultMenuTitle = $sourceFile;
        -
        -    if (scalar @parsedFile)
        -        {
        -        my $addFileTitle;
        -
        -        if (NaturalDocs::Settings->OnlyFileTitles())
        -            {
        -            # We still want to use the title from the topics if the first one is a file.
        -            if ($parsedFile[0]->Type() eq ::TOPIC_FILE())
        -                {  $addFileTitle = 0;  }
        -            else
        -                {  $addFileTitle = 1;  };
        -            }
        -        elsif (scalar @parsedFile == 1 || NaturalDocs::Topics->TypeInfo( $parsedFile[0]->Type() )->PageTitleIfFirst())
        -            {  $addFileTitle = 0;  }
        -        else
        -            {  $addFileTitle = 1;  };
        -
        -        if (!$addFileTitle)
        -            {
        -            $defaultMenuTitle = $parsedFile[0]->Title();
        -            }
        -        else
        -            {
        -            # If the title ended up being the file name, add a leading section for it.
        -
        -            unshift @parsedFile,
        -                       NaturalDocs::Parser::ParsedTopic->New(::TOPIC_FILE(), (NaturalDocs::File->SplitPath($sourceFile))[2],
        -                                                                                  undef, undef, undef, undef, undef, 1, undef);
        -            };
        -        };
        -
        -    NaturalDocs::Error->OnEndParsing($sourceFile);
        -
        -    return $defaultMenuTitle;
        -    };
        -
        -
        -#
        -#   Function: CleanComment
        -#
        -#   Removes any extraneous formatting and whitespace from the comment.  Eliminates comment boxes, horizontal lines, trailing
        -#   whitespace from lines, and expands all tab characters.  It keeps leading whitespace, though, since it may be needed for
        -#   example code, and blank lines, since the original line numbers are needed.
        -#
        -#   Parameters:
        -#
        -#       commentLines  - An arrayref of the comment lines to clean.  *The original memory will be changed.*  Lines should have the
        -#                                language's comment symbols replaced by spaces and not have a trailing line break.
        -#
        -sub CleanComment #(commentLines)
        -    {
        -    my ($self, $commentLines) = @_;
        -
        -    use constant DONT_KNOW => 0;
        -    use constant IS_UNIFORM => 1;
        -    use constant IS_UNIFORM_IF_AT_END => 2;
        -    use constant IS_NOT_UNIFORM => 3;
        -
        -    my $leftSide = DONT_KNOW;
        -    my $rightSide = DONT_KNOW;
        -    my $leftSideChar;
        -    my $rightSideChar;
        -
        -    my $index = 0;
        -    my $tabLength = NaturalDocs::Settings->TabLength();
        -
        -    while ($index < scalar @$commentLines)
        -        {
        -        # Strip trailing whitespace from the original.
        -
        -        $commentLines->[$index] =~ s/[ \t]+$//;
        -
        -
        -        # Expand tabs in the original.  This method is almost six times faster than Text::Tabs' method.
        -
        -        my $tabIndex = index($commentLines->[$index], "\t");
        -
        -        while ($tabIndex != -1)
        -            {
        -            substr( $commentLines->[$index], $tabIndex, 1, ' ' x ($tabLength - ($tabIndex % $tabLength)) );
        -            $tabIndex = index($commentLines->[$index], "\t", $tabIndex);
        -            };
        -
        -
        -        # Make a working copy and strip leading whitespace as well.  This has to be done after tabs are expanded because
        -        # stripping indentation could change how far tabs are expanded.
        -
        -        my $line = $commentLines->[$index];
        -        $line =~ s/^ +//;
        -
        -        # If the line is blank...
        -        if (!length $line)
        -            {
        -            # If we have a potential vertical line, this only acceptable if it's at the end of the comment.
        -            if ($leftSide == IS_UNIFORM)
        -                {  $leftSide = IS_UNIFORM_IF_AT_END;  };
        -            if ($rightSide == IS_UNIFORM)
        -                {  $rightSide = IS_UNIFORM_IF_AT_END;  };
        -            }
        -
        -        # If there's at least four symbols in a row, it's a horizontal line.  The second regex supports differing edge characters.  It
        -        # doesn't matter if any of this matches the left and right side symbols.  The length < 256 is a sanity check, because that
        -        # regexp has caused the perl regexp engine to choke on an insane line someone sent me from an automatically generated
        -        # file.  It had over 10k characters on the first line, and most of them were 0x00.
        -        elsif ($line =~ /^([^a-zA-Z0-9 ])\1{3,}$/ ||
        -                (length $line < 256 && $line =~ /^([^a-zA-Z0-9 ])\1*([^a-zA-Z0-9 ])\2{3,}([^a-zA-Z0-9 ])\3*$/) )
        -            {
        -            # Ignore it.  This has no effect on the vertical line detection.  We want to keep it in the output though in case it was
        -            # in a code section.
        -            }
        -
        -        # If the line is not blank or a horizontal line...
        -        else
        -            {
        -            # More content means any previous blank lines are no longer tolerated in vertical line detection.  They are only
        -            # acceptable at the end of the comment.
        -
        -            if ($leftSide == IS_UNIFORM_IF_AT_END)
        -                {  $leftSide = IS_NOT_UNIFORM;  };
        -            if ($rightSide == IS_UNIFORM_IF_AT_END)
        -                {  $rightSide = IS_NOT_UNIFORM;  };
        -
        -
        -            # Detect vertical lines.  Lines are only lines if they are followed by whitespace or a connected horizontal line.
        -            # Otherwise we may accidentally detect lines from short comments that just happen to have every first or last
        -            # character the same.
        -
        -            if ($leftSide != IS_NOT_UNIFORM)
        -                {
        -                if ($line =~ /^([^a-zA-Z0-9])\1*(?: |$)/)
        -                    {
        -                    if ($leftSide == DONT_KNOW)
        -                        {
        -                        $leftSide = IS_UNIFORM;
        -                        $leftSideChar = $1;
        -                        }
        -                    else # ($leftSide == IS_UNIFORM)  Other choices already ruled out.
        -                        {
        -                        if ($leftSideChar ne $1)
        -                            {  $leftSide = IS_NOT_UNIFORM;  };
        -                        };
        -                    }
        -                # We'll tolerate the lack of symbols on the left on the first line, because it may be a
        -                # /* Function: Whatever
        -                #  * Description.
        -                #  */
        -                # comment which would have the leading /* blanked out.
        -                elsif ($index != 0)
        -                    {
        -                    $leftSide = IS_NOT_UNIFORM;
        -                    };
        -                };
        -
        -            if ($rightSide != IS_NOT_UNIFORM)
        -                {
        -                if ($line =~ / ([^a-zA-Z0-9])\1*$/)
        -                    {
        -                    if ($rightSide == DONT_KNOW)
        -                        {
        -                        $rightSide = IS_UNIFORM;
        -                        $rightSideChar = $1;
        -                        }
        -                    else # ($rightSide == IS_UNIFORM)  Other choices already ruled out.
        -                        {
        -                        if ($rightSideChar ne $1)
        -                            {  $rightSide = IS_NOT_UNIFORM;  };
        -                        };
        -                    }
        -                else
        -                    {
        -                    $rightSide = IS_NOT_UNIFORM;
        -                    };
        -                };
        -
        -            # We'll remove vertical lines later if they're uniform throughout the entire comment.
        -            };
        -
        -        $index++;
        -        };
        -
        -
        -    if ($leftSide == IS_UNIFORM_IF_AT_END)
        -        {  $leftSide = IS_UNIFORM;  };
        -    if ($rightSide == IS_UNIFORM_IF_AT_END)
        -        {  $rightSide = IS_UNIFORM;  };
        -
        -
        -    $index = 0;
        -    my $inCodeSection = 0;
        -
        -    while ($index < scalar @$commentLines)
        -        {
        -        # Clear horizontal lines only if we're not in a code section.
        -        if ($commentLines->[$index] =~ /^ *([^a-zA-Z0-9 ])\1{3,}$/ ||
        -            ( length $commentLines->[$index] < 256 &&
        -              $commentLines->[$index] =~ /^ *([^a-zA-Z0-9 ])\1*([^a-zA-Z0-9 ])\2{3,}([^a-zA-Z0-9 ])\3*$/ ) )
        -        	{
        -        	if (!$inCodeSection)
        -        		{  $commentLines->[$index] = '';  }
        -        	}
        -
        -        else
        -        	{
        -	        # Clear vertical lines.
        -
        -	        if ($leftSide == IS_UNIFORM)
        -	            {
        -	            # This works because every line should either start this way, be blank, or be the first line that doesn't start with a
        -	            # symbol.
        -	            $commentLines->[$index] =~ s/^ *([^a-zA-Z0-9 ])\1*//;
        -	            };
        -
        -	        if ($rightSide == IS_UNIFORM)
        -	            {
        -	            $commentLines->[$index] =~ s/ *([^a-zA-Z0-9 ])\1*$//;
        -	            };
        -
        -
        -	        # Clear horizontal lines again if there were vertical lines.  This catches lines that were separated from the verticals by
        -	        # whitespace.
        -
        -	        if (($leftSide == IS_UNIFORM || $rightSide == IS_UNIFORM) && !$inCodeSection)
        -	            {
        -	            $commentLines->[$index] =~ s/^ *([^a-zA-Z0-9 ])\1{3,}$//;
        -	            $commentLines->[$index] =~ s/^ *([^a-zA-Z0-9 ])\1*([^a-zA-Z0-9 ])\2{3,}([^a-zA-Z0-9 ])\3*$//;
        -	            };
        -
        -
        -	        # Check for the start and end of code sections.  Note that this doesn't affect vertical line removal.
        -
        -	        if (!$inCodeSection &&
        -	        	$commentLines->[$index] =~ /^ *\( *(?:(?:start|begin)? +)?(?:table|code|example|diagram) *\)$/i )
        -	        	{
        -	        	$inCodeSection = 1;
        -	        	}
        -	        elsif ($inCodeSection &&
        -	        	    $commentLines->[$index] =~ /^ *\( *(?:end|finish|done)(?: +(?:table|code|example|diagram))? *\)$/i)
        -	        	 {
        -	        	 $inCodeSection = 0;
        -	        	 }
        -	        }
        -
        -
        -        $index++;
        -        };
        -
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Processing Functions
        -
        -
        -#
        -#   Function: RepairPackages
        -#
        -#   Recalculates the packages for all comment topics using the auto-topics and the scope record.  Call this *before* calling
        -#   <MergeAutoTopics()>.
        -#
        -#   Parameters:
        -#
        -#       autoTopics - A reference to the list of automatically generated <NaturalDocs::Parser::ParsedTopics>.
        -#       scopeRecord - A reference to an array of <NaturalDocs::Languages::Advanced::ScopeChanges>.
        -#
        -sub RepairPackages #(autoTopics, scopeRecord)
        -    {
        -    my ($self, $autoTopics, $scopeRecord) = @_;
        -
        -    my $topicIndex = 0;
        -    my $autoTopicIndex = 0;
        -    my $scopeIndex = 0;
        -
        -    my $topic = $parsedFile[0];
        -    my $autoTopic = $autoTopics->[0];
        -    my $scopeChange = $scopeRecord->[0];
        -
        -    my $currentPackage;
        -    my $inFakePackage;
        -
        -    while (defined $topic)
        -        {
        -        # First update the scope via the record if its defined and has the lowest line number.
        -        if (defined $scopeChange &&
        -            $scopeChange->LineNumber() <= $topic->LineNumber() &&
        -            (!defined $autoTopic || $scopeChange->LineNumber() <= $autoTopic->LineNumber()) )
        -            {
        -            $currentPackage = $scopeChange->Scope();
        -            $scopeIndex++;
        -            $scopeChange = $scopeRecord->[$scopeIndex];  # Will be undef when past end.
        -            $inFakePackage = undef;
        -            }
        -
        -        # Next try to end a fake scope with an auto topic if its defined and has the lowest line number.
        -        elsif (defined $autoTopic &&
        -                $autoTopic->LineNumber() <= $topic->LineNumber())
        -            {
        -            if ($inFakePackage)
        -                {
        -                $currentPackage = $autoTopic->Package();
        -                $inFakePackage = undef;
        -                };
        -
        -            $autoTopicIndex++;
        -            $autoTopic = $autoTopics->[$autoTopicIndex];  # Will be undef when past end.
        -            }
        -
        -
        -        # Finally try to handle the topic, since it has the lowest line number.  Check for Type() because headerless topics won't have
        -        # one.
        -        else
        -            {
        -            my $scope;
        -            if ($topic->Type())
        -                {  $scope = NaturalDocs::Topics->TypeInfo($topic->Type())->Scope();  }
        -            else
        -                {  $scope = ::SCOPE_NORMAL();  };
        -
        -            if ($scope == ::SCOPE_START() || $scope == ::SCOPE_END())
        -                {
        -                # They should already have the correct class and scope.
        -                $currentPackage = $topic->Package();
        -                $inFakePackage = 1;
        -                }
        -           else
        -                {
        -                # Fix the package of everything else.
        -
        -                # Note that the first function or variable topic to appear in a fake package will assume that package even if it turns out
        -                # to be incorrect in the actual code, since the topic will come before the auto-topic.  This will be corrected in
        -                # MergeAutoTopics().
        -
        -                $topic->SetPackage($currentPackage);
        -                };
        -
        -            $topicIndex++;
        -            $topic = $parsedFile[$topicIndex];  # Will be undef when past end.
        -            };
        -        };
        -
        -    };
        -
        -
        -#
        -#   Function: MergeAutoTopics
        -#
        -#   Merges the automatically generated topics into the file.  If an auto-topic matches an existing topic, it will have it's prototype
        -#   and package transferred.  If it doesn't, the auto-topic will be inserted into the list unless
        -#   <NaturalDocs::Settings->DocumentedOnly()> is set.  If an existing topic doesn't have a title, it's assumed to be a headerless
        -#   comment and will be merged with the next auto-topic or discarded.
        -#
        -#   Parameters:
        -#
        -#       language - The <NaturalDocs::Languages::Base>-derived class for the file.
        -#       autoTopics - A reference to the list of automatically generated topics.
        -#
        -sub MergeAutoTopics #(language, autoTopics)
        -    {
        -    my ($self, $language, $autoTopics) = @_;
        -
        -    my $topicIndex = 0;
        -    my $autoTopicIndex = 0;
        -
        -    # Keys are topic types, values are existence hashrefs of titles.
        -    my %topicsInLists;
        -
        -    while ($topicIndex < scalar @parsedFile && $autoTopicIndex < scalar @$autoTopics)
        -        {
        -        my $topic = $parsedFile[$topicIndex];
        -        my $autoTopic = $autoTopics->[$autoTopicIndex];
        -
        -        my $cleanTitle = $topic->Title();
        -        $cleanTitle =~ s/[\t ]*\([^\(]*$//;
        -
        -        # Add the auto-topic if it's higher in the file than the current topic.
        -        if ($autoTopic->LineNumber() < $topic->LineNumber())
        -            {
        -            if (exists $topicsInLists{$autoTopic->Type()} &&
        -                exists $topicsInLists{$autoTopic->Type()}->{$autoTopic->Title()})
        -                {
        -                # Remove it from the list so a second one with the same name will be added.
        -                delete $topicsInLists{$autoTopic->Type()}->{$autoTopic->Title()};
        -                }
        -            elsif (!NaturalDocs::Settings->DocumentedOnly())
        -                {
        -                splice(@parsedFile, $topicIndex, 0, $autoTopic);
        -                $topicIndex++;
        -                };
        -
        -            $autoTopicIndex++;
        -            }
        -
        -        # Remove a headerless topic if there's another topic between it and the next auto-topic.
        -        elsif (!$topic->Title() && $topicIndex + 1 < scalar @parsedFile &&
        -                $parsedFile[$topicIndex+1]->LineNumber() < $autoTopic->LineNumber())
        -            {
        -            splice(@parsedFile, $topicIndex, 1);
        -            }
        -
        -        # Transfer information if we have a match or a headerless topic.
        -        elsif ( !$topic->Title() ||
        -        		  $topic->Symbol() eq $autoTopic->Symbol() ||
        -        		  ( $topic->Type() == $autoTopic->Type() &&
        -        			( index($autoTopic->Title(), $cleanTitle) != -1 || index($cleanTitle, $autoTopic->Title()) != -1 ) ) )
        -            {
        -            $topic->SetType($autoTopic->Type());
        -            $topic->SetPrototype($autoTopic->Prototype());
        -            $topic->SetUsing($autoTopic->Using());
        -
        -            if (!$topic->Title())
        -                {  $topic->SetTitle($autoTopic->Title());  };
        -
        -            if (NaturalDocs::Topics->TypeInfo($topic->Type())->Scope() != ::SCOPE_START())
        -                {  $topic->SetPackage($autoTopic->Package());  }
        -            elsif ($autoTopic->Package() ne $topic->Package())
        -                {
        -                my @autoPackageIdentifiers = NaturalDocs::SymbolString->IdentifiersOf($autoTopic->Package());
        -                my @packageIdentifiers = NaturalDocs::SymbolString->IdentifiersOf($topic->Package());
        -
        -                while (scalar @autoPackageIdentifiers && $autoPackageIdentifiers[-1] eq $packageIdentifiers[-1])
        -                    {
        -                    pop @autoPackageIdentifiers;
        -                    pop @packageIdentifiers;
        -                    };
        -
        -                if (scalar @autoPackageIdentifiers)
        -                    {  $topic->SetPackage( NaturalDocs::SymbolString->Join(@autoPackageIdentifiers) );  };
        -                };
        -
        -            $topicIndex++;
        -            $autoTopicIndex++;
        -            }
        -
        -        # Extract topics in lists.
        -        elsif ($topic->IsList())
        -            {
        -            if (!exists $topicsInLists{$topic->Type()})
        -                {  $topicsInLists{$topic->Type()} = { };  };
        -
        -            my $body = $topic->Body();
        -
        -            while ($body =~ /<ds>([^<]+)<\/ds>/g)
        -                {  $topicsInLists{$topic->Type()}->{NaturalDocs::NDMarkup->RestoreAmpChars($1)} = 1;  };
        -
        -            $topicIndex++;
        -            }
        -
        -        # Otherwise there's no match.  Skip the topic.  The auto-topic will be added later.
        -        else
        -            {
        -            $topicIndex++;
        -            }
        -        };
        -
        -    # Add any auto-topics remaining.
        -    if (!NaturalDocs::Settings->DocumentedOnly())
        -    	{
        -	    while ($autoTopicIndex < scalar @$autoTopics)
        -	        {
        -	        my $autoTopic = $autoTopics->[$autoTopicIndex];
        -
        -	        if (exists $topicsInLists{$autoTopic->Type()} &&
        -	            exists $topicsInLists{$autoTopic->Type()}->{$autoTopic->Title()})
        -	            {
        -	            # Remove it from the list so a second one with the same name will be added.
        -	            delete $topicsInLists{$autoTopic->Type()}->{$autoTopic->Title()};
        -	            }
        -	        else
        -	            {
        -	            push(@parsedFile, $autoTopic);
        -	            };
        -
        -	        $autoTopicIndex++;
        -	        };
        -        };
        -   };
        -
        -
        -#
        -#   Function: RemoveRemainingHeaderlessTopics
        -#
        -#   After <MergeAutoTopics()> is done, this function removes any remaining headerless topics from the file.  If they don't merge
        -#   into anything, they're not valid topics.
        -#
        -sub RemoveRemainingHeaderlessTopics
        -    {
        -    my ($self) = @_;
        -
        -    my $index = 0;
        -    while ($index < scalar @parsedFile)
        -        {
        -        if ($parsedFile[$index]->Title())
        -            {  $index++;  }
        -        else
        -            {  splice(@parsedFile, $index, 1);  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: MakeAutoGroups
        -#
        -#   Creates group topics for files that do not have them.
        -#
        -sub MakeAutoGroups
        -    {
        -    my ($self) = @_;
        -
        -    # No groups only one topic.
        -    if (scalar @parsedFile < 2)
        -        {  return;  };
        -
        -    my $index = 0;
        -    my $startStretch = 0;
        -
        -    # Skip the first entry if its the page title.
        -    if (NaturalDocs::Topics->TypeInfo( $parsedFile[0]->Type() )->PageTitleIfFirst())
        -        {
        -        $index = 1;
        -        $startStretch = 1;
        -        };
        -
        -    # Make auto-groups for each stretch between scope-altering topics.
        -    while ($index < scalar @parsedFile)
        -        {
        -        my $scope = NaturalDocs::Topics->TypeInfo($parsedFile[$index]->Type())->Scope();
        -
        -        if ($scope == ::SCOPE_START() || $scope == ::SCOPE_END())
        -            {
        -            if ($index > $startStretch)
        -                {  $index += $self->MakeAutoGroupsFor($startStretch, $index);  };
        -
        -            $startStretch = $index + 1;
        -            };
        -
        -        $index++;
        -        };
        -
        -    if ($index > $startStretch)
        -        {  $self->MakeAutoGroupsFor($startStretch, $index);  };
        -    };
        -
        -
        -#
        -#   Function: MakeAutoGroupsFor
        -#
        -#   Creates group topics for sections of files that do not have them.  A support function for <MakeAutoGroups()>.
        -#
        -#   Parameters:
        -#
        -#       startIndex - The index to start at.
        -#       endIndex - The index to end at.  Not inclusive.
        -#
        -#   Returns:
        -#
        -#       The number of group topics added.
        -#
        -sub MakeAutoGroupsFor #(startIndex, endIndex)
        -    {
        -    my ($self, $startIndex, $endIndex) = @_;
        -
        -    # No groups if any are defined already.
        -    for (my $i = $startIndex; $i < $endIndex; $i++)
        -        {
        -        if ($parsedFile[$i]->Type() eq ::TOPIC_GROUP())
        -            {  return 0;  };
        -        };
        -
        -
        -    use constant COUNT => 0;
        -    use constant TYPE => 1;
        -    use constant SECOND_TYPE => 2;
        -    use constant SIZE => 3;
        -
        -    # This is an array of ( count, type, secondType ) triples.  Count and Type will always be filled in; count is the number of
        -    # consecutive topics of type.  On the second pass, if small groups are combined secondType will be filled in.  There will not be
        -    # more than two types per group.
        -    my @groups;
        -    my $groupIndex = 0;
        -
        -
        -    # First pass: Determine all the groups.
        -
        -    my $i = $startIndex;
        -    my $currentType;
        -
        -    while ($i < $endIndex)
        -        {
        -        if (!defined $currentType || ($parsedFile[$i]->Type() ne $currentType && $parsedFile[$i]->Type() ne ::TOPIC_GENERIC()) )
        -            {
        -            if (defined $currentType)
        -                {  $groupIndex += SIZE;  };
        -
        -            $currentType = $parsedFile[$i]->Type();
        -
        -            $groups[$groupIndex + COUNT] = 1;
        -            $groups[$groupIndex + TYPE] = $currentType;
        -            }
        -        else
        -            {  $groups[$groupIndex + COUNT]++;  };
        -
        -        $i++;
        -        };
        -
        -
        -    # Second pass: Combine groups based on "noise".  Noise means types go from A to B to A at least once, and there are at least
        -    # two groups in a row with three or less, and at least one of those groups is two or less.  So 3, 3, 3 doesn't count as noise, but
        -    # 3, 2, 3 does.
        -
        -    $groupIndex = 0;
        -
        -    # While there are at least three groups left...
        -    while ($groupIndex < scalar @groups - (2 * SIZE))
        -        {
        -        # If the group two places in front of this one has the same type...
        -        if ($groups[$groupIndex + (2 * SIZE) + TYPE] eq $groups[$groupIndex + TYPE])
        -            {
        -            # It means we went from A to B to A, which partially qualifies as noise.
        -
        -            my $firstType = $groups[$groupIndex + TYPE];
        -            my $secondType = $groups[$groupIndex + SIZE + TYPE];
        -
        -            if (NaturalDocs::Topics->TypeInfo($firstType)->CanGroupWith($secondType) ||
        -                NaturalDocs::Topics->TypeInfo($secondType)->CanGroupWith($firstType))
        -                {
        -                my $hasNoise;
        -
        -                my $hasThrees;
        -                my $hasTwosOrOnes;
        -
        -                my $endIndex = $groupIndex;
        -
        -                while ($endIndex < scalar @groups &&
        -                         ($groups[$endIndex + TYPE] eq $firstType || $groups[$endIndex + TYPE] eq $secondType))
        -                    {
        -                    if ($groups[$endIndex + COUNT] > 3)
        -                        {
        -                        # They must be consecutive to count.
        -                        $hasThrees = 0;
        -                        $hasTwosOrOnes = 0;
        -                        }
        -                    elsif ($groups[$endIndex + COUNT] == 3)
        -                        {
        -                        $hasThrees = 1;
        -
        -                        if ($hasTwosOrOnes)
        -                            {  $hasNoise = 1;  };
        -                        }
        -                    else # < 3
        -                        {
        -                        if ($hasThrees || $hasTwosOrOnes)
        -                            {  $hasNoise = 1;  };
        -
        -                        $hasTwosOrOnes = 1;
        -                        };
        -
        -                    $endIndex += SIZE;
        -                    };
        -
        -                if (!$hasNoise)
        -                    {
        -                    $groupIndex = $endIndex - SIZE;
        -                    }
        -                else # hasNoise
        -                    {
        -                    $groups[$groupIndex + SECOND_TYPE] = $secondType;
        -
        -                    for (my $noiseIndex = $groupIndex + SIZE; $noiseIndex < $endIndex; $noiseIndex += SIZE)
        -                        {
        -                        $groups[$groupIndex + COUNT] += $groups[$noiseIndex + COUNT];
        -                        };
        -
        -                    splice(@groups, $groupIndex + SIZE, $endIndex - $groupIndex - SIZE);
        -
        -                    $groupIndex += SIZE;
        -                    };
        -                }
        -
        -            else # They can't group together
        -                {
        -                $groupIndex += SIZE;
        -                };
        -            }
        -
        -        else
        -            {  $groupIndex += SIZE;  };
        -        };
        -
        -
        -    # Finally, create group topics for the parsed file.
        -
        -    $groupIndex = 0;
        -    $i = $startIndex;
        -
        -    while ($groupIndex < scalar @groups)
        -        {
        -        if ($groups[$groupIndex + TYPE] ne ::TOPIC_GENERIC())
        -            {
        -            my $topic = $parsedFile[$i];
        -            my $title = NaturalDocs::Topics->NameOfType($groups[$groupIndex + TYPE], 1);
        -
        -            if (defined $groups[$groupIndex + SECOND_TYPE])
        -                {  $title .= ' and ' . NaturalDocs::Topics->NameOfType($groups[$groupIndex + SECOND_TYPE], 1);  };
        -
        -            splice(@parsedFile, $i, 0, NaturalDocs::Parser::ParsedTopic->New(::TOPIC_GROUP(),
        -                                                                                                            $title,
        -                                                                                                            $topic->Package(), $topic->Using(),
        -                                                                                                            undef, undef, undef,
        -                                                                                                            $topic->LineNumber()) );
        -            $i++;
        -            };
        -
        -        $i += $groups[$groupIndex + COUNT];
        -        $groupIndex += SIZE;
        -        };
        -
        -    return (scalar @groups / SIZE);
        -    };
        -
        -
        -#
        -#   Function: AddToClassHierarchy
        -#
        -#   Adds any class topics to the class hierarchy, since they may not have been called with <OnClass()> if they didn't match up to
        -#   an auto-topic.
        -#
        -sub AddToClassHierarchy
        -    {
        -    my ($self) = @_;
        -
        -    foreach my $topic (@parsedFile)
        -        {
        -        if ($topic->Type() && NaturalDocs::Topics->TypeInfo( $topic->Type() )->ClassHierarchy())
        -            {
        -            if ($topic->IsList())
        -                {
        -                my $body = $topic->Body();
        -
        -                while ($body =~ /<ds>([^<]+)<\/ds>/g)
        -                    {
        -                    $self->OnClass( NaturalDocs::SymbolString->FromText( NaturalDocs::NDMarkup->RestoreAmpChars($1) ) );
        -                    };
        -                }
        -            else
        -                {
        -                $self->OnClass($topic->Package());
        -                };
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: AddPackageDelineators
        -#
        -#   Adds section and class topics to make sure the package is correctly represented in the documentation.  Should be called last in
        -#   this process.
        -#
        -sub AddPackageDelineators
        -    {
        -    my ($self) = @_;
        -
        -    my $index = 0;
        -    my $currentPackage;
        -
        -    # Values are the arrayref [ title, type ];
        -    my %usedPackages;
        -
        -    while ($index < scalar @parsedFile)
        -        {
        -        my $topic = $parsedFile[$index];
        -
        -        if ($topic->Package() ne $currentPackage)
        -            {
        -            $currentPackage = $topic->Package();
        -            my $scopeType = NaturalDocs::Topics->TypeInfo($topic->Type())->Scope();
        -
        -            if ($scopeType == ::SCOPE_START())
        -                {
        -                $usedPackages{$currentPackage} = [ $topic->Title(), $topic->Type() ];
        -                }
        -            elsif ($scopeType == ::SCOPE_END())
        -                {
        -                my $newTopic;
        -
        -                if (!defined $currentPackage)
        -                    {
        -                    $newTopic = NaturalDocs::Parser::ParsedTopic->New(::TOPIC_SECTION(), 'Global',
        -                                                                                                   undef, undef,
        -                                                                                                   undef, undef, undef,
        -                                                                                                   $topic->LineNumber(), undef);
        -                    }
        -                else
        -                    {
        -                    my ($title, $body, $summary, $type);
        -                    my @packageIdentifiers = NaturalDocs::SymbolString->IdentifiersOf($currentPackage);
        -
        -                    if (exists $usedPackages{$currentPackage})
        -                        {
        -                        $title = $usedPackages{$currentPackage}->[0];
        -                        $type = $usedPackages{$currentPackage}->[1];
        -                        $body = '<p>(continued)</p>';
        -                        $summary = '(continued)';
        -                        }
        -                    else
        -                        {
        -                        $title = join($language->PackageSeparator(), @packageIdentifiers);
        -                        $type = ::TOPIC_CLASS();
        -
        -                        # Body and summary stay undef.
        -
        -                        $usedPackages{$currentPackage} = $title;
        -                        };
        -
        -                    my @titleIdentifiers = NaturalDocs::SymbolString->IdentifiersOf( NaturalDocs::SymbolString->FromText($title) );
        -                    for (my $i = 0; $i < scalar @titleIdentifiers; $i++)
        -                        {  pop @packageIdentifiers;  };
        -
        -                    $newTopic = NaturalDocs::Parser::ParsedTopic->New($type, $title,
        -                                                                                                   NaturalDocs::SymbolString->Join(@packageIdentifiers), undef,
        -                                                                                                   undef, $summary, $body,
        -                                                                                                   $topic->LineNumber(), undef);
        -                    }
        -
        -                splice(@parsedFile, $index, 0, $newTopic);
        -                $index++;
        -                }
        -            };
        -
        -        $index++;
        -        };
        -    };
        -
        -
        -#
        -#   Function: BreakLists
        -#
        -#   Breaks list topics into individual topics.
        -#
        -sub BreakLists
        -    {
        -    my $self = shift;
        -
        -    my $index = 0;
        -
        -    while ($index < scalar @parsedFile)
        -        {
        -        my $topic = $parsedFile[$index];
        -
        -        if ($topic->IsList() && NaturalDocs::Topics->TypeInfo( $topic->Type() )->BreakLists())
        -            {
        -            my $body = $topic->Body();
        -
        -            my @newTopics;
        -            my $newBody;
        -
        -            my $bodyIndex = 0;
        -
        -            for (;;)
        -                {
        -                my $startList = index($body, '<dl>', $bodyIndex);
        -
        -                if ($startList == -1)
        -                    {  last;  };
        -
        -                $newBody .= substr($body, $bodyIndex, $startList - $bodyIndex);
        -
        -                my $endList = index($body, '</dl>', $startList);
        -                my $listBody = substr($body, $startList, $endList - $startList);
        -
        -                while ($listBody =~ /<ds>([^<]+)<\/ds><dd>(.*?)<\/dd>/g)
        -                    {
        -                    my ($symbol, $description) = ($1, $2);
        -
        -                    push @newTopics, NaturalDocs::Parser::ParsedTopic->New( $topic->Type(), $symbol, $topic->Package(),
        -                                                                                                            $topic->Using(), undef,
        -                                                                                                            $self->GetSummaryFromDescriptionList($description),
        -                                                                                                            '<p>' . $description .  '</p>', $topic->LineNumber(),
        -                                                                                                            undef );
        -                    };
        -
        -                $bodyIndex = $endList + 5;
        -                };
        -
        -            $newBody .= substr($body, $bodyIndex);
        -
        -            # Remove trailing headings.
        -            $newBody =~ s/(?:<h>[^<]+<\/h>)+$//;
        -
        -            # Remove empty headings.
        -            $newBody =~ s/(?:<h>[^<]+<\/h>)+(<h>[^<]+<\/h>)/$1/g;
        -
        -            if ($newBody)
        -                {
        -                unshift @newTopics, NaturalDocs::Parser::ParsedTopic->New( ::TOPIC_GROUP(), $topic->Title(), $topic->Package(),
        -                                                                                                          $topic->Using(), undef,
        -                                                                                                          $self->GetSummaryFromBody($newBody), $newBody,
        -                                                                                                          $topic->LineNumber(), undef );
        -                };
        -
        -            splice(@parsedFile, $index, 1, @newTopics);
        -
        -            $index += scalar @newTopics;
        -            }
        -
        -        else # not a list
        -            {  $index++;  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: GetSummaryFromBody
        -#
        -#   Returns the summary text from the topic body.
        -#
        -#   Parameters:
        -#
        -#       body - The complete topic body, in <NDMarkup>.
        -#
        -#   Returns:
        -#
        -#       The topic summary, or undef if none.
        -#
        -sub GetSummaryFromBody #(body)
        -    {
        -    my ($self, $body) = @_;
        -
        -    my $summary;
        -
        -    # Extract the first sentence from the leading paragraph, if any.  We'll tolerate a single header beforehand, but nothing else.
        -
        -    if ($body =~ /^(?:<h>[^<]*<\/h>)?<p>(.*?)(<\/p>|[\.\!\?](?:[\)\}\'\ ]|&quot;|&gt;))/x)
        -        {
        -        $summary = $1;
        -
        -        if ($2 ne '</p>')
        -            {  $summary .= $2;  };
        -        };
        -
        -    return $summary;
        -    };
        -
        -
        -#
        -#   Function: GetSummaryFromDescriptionList
        -#
        -#   Returns the summary text from a description list entry.
        -#
        -#   Parameters:
        -#
        -#       description - The description in <NDMarkup>.  Should be the content between the <dd></dd> tags only.
        -#
        -#   Returns:
        -#
        -#       The description summary, or undef if none.
        -#
        -sub GetSummaryFromDescriptionList #(description)
        -    {
        -    my ($self, $description) = @_;
        -
        -    my $summary;
        -
        -    if ($description =~ /^(.*?)($|[\.\!\?](?:[\)\}\'\ ]|&quot;|&gt;))/)
        -        {  $summary = $1 . $2;  };
        -
        -    return $summary;
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Parser/JavaDoc.pm b/vendor/naturaldocs/Modules/NaturalDocs/Parser/JavaDoc.pm
        deleted file mode 100644
        index 0e8bd4bd0..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Parser/JavaDoc.pm
        +++ /dev/null
        @@ -1,465 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Parser::JavaDoc
        -#
        -###############################################################################
        -#
        -#   A package for translating JavaDoc topics into Natural Docs.
        -#
        -#   Supported tags:
        -#
        -#       - @param
        -#       - @author
        -#       - @deprecated
        -#       - @code, @literal (doesn't change font)
        -#       - @exception, @throws (doesn't link to class)
        -#       - @link, @linkplain (doesn't change font)
        -#       - @return, @returns
        -#       - @see
        -#       - @since
        -#       - @value (shown as link instead of replacement)
        -#       - @version
        -#
        -#   Stripped tags:
        -#
        -#       - @inheritDoc
        -#       - @serial, @serialField, @serialData
        -#       - All other block level tags.
        -#
        -#   Unsupported tags:
        -#
        -#       These will appear literally in the output because I cannot handle them easily.
        -#
        -#       - @docRoot
        -#       - Any other tags not mentioned
        -#
        -#   Supported HTML:
        -#
        -#       - p
        -#       - b, i, u
        -#       - pre
        -#       - a href
        -#       - ol, ul, li (ol gets converted to ul)
        -#       - gt, lt, amp, quot, nbsp entities
        -#
        -#   Stripped HTML:
        -#
        -#       - code
        -#       - HTML comments
        -#
        -#   Unsupported HTML:
        -#
        -#       These will appear literally in the output because I cannot handle them easily.
        -#
        -#       - Any tags with additional properties other than a href.  (ex. <p class=Something>)
        -#       - Any other tags not mentioned
        -#
        -#   Reference:
        -#
        -#       http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/javadoc.html
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Parser::JavaDoc;
        -
        -
        -#
        -#   hash: blockTags
        -#   An existence hash of the all-lowercase JavaDoc block tags, not including the @.
        -#
        -my %blockTags = ( 'param' => 1, 'author' => 1, 'deprecated' => 1, 'exception' => 1, 'return' => 1, 'see' => 1,
        -                             'serial' => 1, 'serialfield' => 1, 'serialdata' => 1, 'since' => 1, 'throws' => 1, 'version' => 1,
        -                             'returns' => 1 );
        -
        -#
        -#   hash: inlineTags
        -#   An existence hash of the all-lowercase JavaDoc inline tags, not including the @.
        -#
        -my %inlineTags = ( 'inheritdoc' => 1, 'docroot' => 1, 'code' => 1, 'literal' => 1, 'link' => 1, 'linkplain' => 1, 'value' => 1 );
        -
        -
        -##
        -#   Examines the comment and returns whether it is *definitely* JavaDoc content, i.e. is owned by this package.
        -#
        -#   Parameters:
        -#
        -#       commentLines - An arrayref of the comment lines.  Must have been run through <NaturalDocs::Parser->CleanComment()>.
        -#       isJavaDoc - Whether the comment is JavaDoc styled.  This doesn't necessarily mean it has JavaDoc content.
        -#
        -#   Returns:
        -#
        -#       Whether the comment is *definitely* JavaDoc content.
        -#
        -sub IsMine #(string[] commentLines, bool isJavaDoc)
        -    {
        -    my ($self, $commentLines, $isJavaDoc) = @_;
        -
        -    if (!$isJavaDoc)
        -        {  return undef;  };
        -
        -    for (my $line = 0; $line < scalar @$commentLines; $line++)
        -        {
        -        if ($commentLines->[$line] =~ /^ *@([a-z]+) /i && exists $blockTags{$1} ||
        -            $commentLines->[$line] =~ /\{@([a-z]+) /i && exists $inlineTags{$1})
        -            {
        -            return 1;
        -            };
        -        };
        -
        -    return 0;
        -    };
        -
        -
        -##
        -#   Parses the JavaDoc-syntax comment and adds it to the parsed topic list.
        -#
        -#   Parameters:
        -#
        -#       commentLines - An arrayref of the comment lines.  Must have been run through <NaturalDocs::Parser->CleanComment()>.
        -#                               *The original memory will be changed.*
        -#       isJavaDoc - Whether the comment is JavaDoc styled.  This doesn't necessarily mean it has JavaDoc content.
        -#       lineNumber - The line number of the first of the comment lines.
        -#       parsedTopics - A reference to the array where any new <NaturalDocs::Parser::ParsedTopics> should be placed.
        -#
        -#   Returns:
        -#
        -#       The number of parsed topics added to the array, which in this case will always be one.
        -#
        -sub ParseComment #(string[] commentLines, bool isJavaDoc, int lineNumber, ParsedTopics[]* parsedTopics)
        -    {
        -    my ($self, $commentLines, $isJavaDoc, $lineNumber, $parsedTopics) = @_;
        -
        -
        -    # Stage one: Before block level tags.
        -
        -    my $i = 0;
        -    my $output;
        -    my $unformattedText;
        -    my $inCode;
        -    my $sharedCodeIndent;
        -
        -    while ($i < scalar @$commentLines &&
        -              !($commentLines->[$i] =~ /^ *@([a-z]+) /i && exists $blockTags{$1}) )
        -        {
        -        my $line = $self->ConvertAmpChars($commentLines->[$i]);
        -        my @tokens = split(/(&lt;\/?pre&gt;)/, $line);
        -
        -        foreach my $token (@tokens)
        -            {
        -            if ($token =~ /^&lt;pre&gt;$/i)
        -                {
        -                if (!$inCode && $unformattedText)
        -                    {
        -                    $output .= '<p>' . $self->FormatText($unformattedText, 1) . '</p>';
        -                    };
        -
        -                $inCode = 1;
        -                $unformattedText = undef;
        -                }
        -            elsif ($token =~ /^&lt;\/pre&gt;$/i)
        -                {
        -                if ($inCode && $unformattedText)
        -                    {
        -                    $unformattedText =~ s/^ {$sharedCodeIndent}//mg;
        -                    $unformattedText =~ s/\n{3,}/\n\n/g;
        -                    $unformattedText =~ s/\n+$//;
        -                    $output .= '<code type="anonymous">' . $unformattedText . '</code>';
        -
        -                    $sharedCodeIndent = undef;
        -                    };
        -
        -                $inCode = 0;
        -                $unformattedText = undef;
        -                }
        -            elsif (length($token))
        -                {
        -                if (!$inCode)
        -                    {
        -                    $token =~ s/^ +//;
        -                    if ($unformattedText)
        -                        {  $unformattedText .= ' ';  };
        -                    }
        -                else
        -                    {
        -                    $token =~ /^( *)/;
        -                    my $indent = length($1);
        -
        -                    if (!defined $sharedCodeIndent || $indent < $sharedCodeIndent)
        -                        {  $sharedCodeIndent = $indent;  };
        -                    };
        -
        -                $unformattedText .= $token;
        -                };
        -            };
        -
        -        if ($inCode && $unformattedText)
        -            {  $unformattedText .= "\n";  };
        -
        -        $i++;
        -        };
        -
        -    if ($unformattedText)
        -        {
        -        if ($inCode)
        -            {
        -            $unformattedText =~ s/^ {$sharedCodeIndent}//mg;
        -            $unformattedText =~ s/\n{3,}/\n\n/g;
        -            $unformattedText =~ s/\n+$//;
        -            $output .= '<code type="anonymous">' . $unformattedText . '</code>';
        -            }
        -        else
        -            {  $output .= '<p>' . $self->FormatText($unformattedText, 1) . '</p>';  };
        -
        -        $unformattedText = undef;
        -        };
        -
        -
        -    # Stage two: Block level tags.
        -
        -    my ($keyword, $value, $unformattedTextPtr, $unformattedTextCloser);
        -    my ($params, $authors, $deprecation, $throws, $returns, $seeAlso, $since, $version);
        -
        -
        -    while ($i < scalar @$commentLines)
        -        {
        -        my $line = $self->ConvertAmpChars($commentLines->[$i]);
        -        $line =~ s/^ +//;
        -
        -        if ($line =~ /^@([a-z]+) ?(.*)$/i)
        -            {
        -            ($keyword, $value) = (lc($1), $2);
        -
        -            # Process the previous one, if any.
        -            if ($unformattedText)
        -                {
        -                $$unformattedTextPtr .= $self->FormatText($unformattedText) . $unformattedTextCloser;
        -                $unformattedText = undef;
        -                };
        -
        -            if ($keyword eq 'param')
        -                {
        -                $value =~ /^([a-z0-9_]+) *(.*)$/i;
        -
        -                $params .= '<de>' . $1 . '</de><dd>';
        -                $unformattedText = $2;
        -
        -                $unformattedTextPtr = \$params;
        -                $unformattedTextCloser = '</dd>';
        -                }
        -            elsif ($keyword eq 'exception' || $keyword eq 'throws')
        -                {
        -                $value =~ /^([a-z0-9_]+) *(.*)$/i;
        -
        -                $throws .= '<de>' . $1 . '</de><dd>';
        -                $unformattedText = $2;
        -
        -                $unformattedTextPtr = \$throws;
        -                $unformattedTextCloser = '</dd>';
        -                }
        -            elsif ($keyword eq 'return' || $keyword eq 'returns')
        -                {
        -                if ($returns)
        -                    {  $returns .= ' ';  };
        -
        -                $unformattedText = $value;
        -                $unformattedTextPtr = \$returns;
        -                $unformattedTextCloser = undef;
        -                }
        -            elsif ($keyword eq 'author')
        -                {
        -                if ($authors)
        -                    {  $authors .= ', ';  };
        -
        -                $unformattedText = $value;
        -                $unformattedTextPtr = \$authors;
        -                $unformattedTextCloser = undef;
        -                }
        -            elsif ($keyword eq 'deprecated')
        -                {
        -                if ($deprecation)
        -                    {  $deprecation .= ' ';  };
        -
        -                $unformattedText = $value;
        -                $unformattedTextPtr = \$deprecation;
        -                $unformattedTextCloser = undef;
        -                }
        -            elsif ($keyword eq 'since')
        -                {
        -                if ($since)
        -                    {  $since .= ', ';  };
        -
        -                $unformattedText = $value;
        -                $unformattedTextPtr = \$since;
        -                $unformattedTextCloser = undef;
        -                }
        -            elsif ($keyword eq 'version')
        -                {
        -                if ($version)
        -                    {  $version .= ', ';  };
        -
        -                $unformattedText = $value;
        -                $unformattedTextPtr = \$version;
        -                $unformattedTextCloser = undef;
        -                }
        -            elsif ($keyword eq 'see')
        -                {
        -                if ($seeAlso)
        -                    {  $seeAlso .= ', ';  };
        -
        -                $unformattedText = undef;
        -
        -                if ($value =~ /^&(?:quot|lt);/i)
        -                    {  $seeAlso .= $self->FormatText($value);  }
        -                else
        -                    {  $seeAlso .= $self->ConvertLink($value);  };
        -                };
        -
        -            # Everything else will be skipped.
        -            }
        -        elsif ($unformattedText)
        -            {
        -            $unformattedText .= ' ' . $line;
        -            };
        -
        -        $i++;
        -        };
        -
        -    if ($unformattedText)
        -        {
        -        $$unformattedTextPtr .= $self->FormatText($unformattedText) . $unformattedTextCloser;
        -        $unformattedText = undef;
        -        };
        -
        -    if ($params)
        -        {  $output .= '<h>Parameters</h><dl>' . $params . '</dl>';  };
        -    if ($returns)
        -        {  $output .= '<h>Returns</h><p>' . $returns . '</p>';  };
        -    if ($throws)
        -        {  $output .= '<h>Throws</h><dl>' . $throws . '</dl>';  };
        -    if ($since)
        -        {  $output .= '<h>Since</h><p>' . $since . '</p>';  };
        -    if ($version)
        -        {  $output .= '<h>Version</h><p>' . $version . '</p>';  };
        -    if ($deprecation)
        -        {  $output .= '<h>Deprecated</h><p>' . $deprecation . '</p>';  };
        -    if ($authors)
        -        {  $output .= '<h>Author</h><p>' . $authors . '</p>';  };
        -    if ($seeAlso)
        -        {  $output .= '<h>See Also</h><p>' . $seeAlso . '</p>';  };
        -
        -
        -    # Stage three: Build the parsed topic.
        -
        -    my $summary = NaturalDocs::Parser->GetSummaryFromBody($output);
        -
        -    push @$parsedTopics, NaturalDocs::Parser::ParsedTopic->New(undef, undef, undef, undef, undef, $summary,
        -                                                                                                $output, $lineNumber, undef);
        -    return 1;
        -    };
        -
        -
        -##
        -#   Translates any inline tags or HTML codes to <NDMarkup> and returns it.
        -#
        -sub FormatText #(string text, bool inParagraph)
        -    {
        -    my ($self, $text, $inParagraph) = @_;
        -
        -    # JavaDoc Literal
        -
        -    $text =~ s/\{\@(?:code|literal) ([^\}]*)\}/$self->ConvertAmpChars($1)/gie;
        -
        -
        -    # HTML
        -
        -    $text =~ s/&lt;b&gt;(.*?)&lt;\/b&gt;/<b>$1<\/b>/gi;
        -    $text =~ s/&lt;i&gt;(.*?)&lt;\/i&gt;/<i>$1<\/i>/gi;
        -    $text =~ s/&lt;u&gt;(.*?)&lt;\/u&gt;/<u>$1<\/u>/gi;
        -
        -    $text =~ s/&lt;code&gt;(.*?)&lt;\/code&gt;/$1/gi;
        -
        -    $text =~ s/&lt;ul.*?&gt;(.*?)&lt;\/ul&gt;/<ul>$1<\/ul>/gi;
        -    $text =~ s/&lt;ol.*?&gt;(.*?)&lt;\/ol&gt;/<ul>$1<\/ul>/gi;
        -    $text =~ s/&lt;li.*?&gt;(.*?)&lt;\/li&gt;/<li>$1<\/li>/gi;
        -
        -    $text =~ s/&lt;!--.*?--&gt;//gi;
        -
        -    $text =~ s/&lt;\/p&gt;//gi;
        -    $text =~ s/^&lt;p&gt;//i;
        -    if ($inParagraph)
        -        {  $text =~ s/&lt;p&gt;/<\/p><p>/gi;  }
        -    else
        -        {  $text =~ s/&lt;p&gt;//gi;  };
        -
        -    $text =~ s/&lt;a href=&quot;mailto:(.*?)&quot;.*?&gt;(.*?)&lt;\/a&gt;/$self->MakeEMailLink($1, $2)/gie;
        -    $text =~ s/&lt;a href=&quot;(.*?)&quot;.*?&gt;(.*?)&lt;\/a&gt;/$self->MakeURLLink($1, $2)/gie;
        -
        -    $text =~ s/&amp;nbsp;/ /gi;
        -    $text =~ s/&amp;amp;/&amp;/gi;
        -    $text =~ s/&amp;gt;/&gt;/gi;
        -    $text =~ s/&amp;lt;/&lt;/gi;
        -    $text =~ s/&amp;quot;/&quot;/gi;
        -
        -
        -
        -    # JavaDoc
        -
        -    $text =~ s/\{\@inheritdoc\}//gi;
        -    $text =~ s/\{\@(?:linkplain|link|value) ([^\}]*)\}/$self->ConvertLink($1)/gie;
        -
        -    return $text;
        -    };
        -
        -
        -sub ConvertAmpChars #(text)
        -    {
        -    my ($self, $text) = @_;
        -
        -    $text =~ s/&/&amp;/g;
        -    $text =~ s/</&lt;/g;
        -    $text =~ s/>/&gt;/g;
        -    $text =~ s/"/&quot;/g;
        -
        -    return $text;
        -    };
        -
        -sub ConvertLink #(text)
        -    {
        -    my ($self, $text) = @_;
        -
        -    $text =~ /^ *([a-z0-9\_\.\:\#]+(?:\([^\)]*\))?) *(.*)$/i;
        -    my ($target, $label) = ($1, $2);
        -
        -    # Convert the anchor to part of the link, but remove it altogether if it's the beginning of the link.
        -    $target =~ s/^\#//;
        -    $target =~ s/\#/\./;
        -
        -    $label =~ s/ +$//;
        -
        -    if (!length $label)
        -        {  return '<link target="' . $target . '" name="' . $target . '" original="' . $target . '">';  }
        -    else
        -        {  return '<link target="' . $target . '" name="' . $label . '" original="' . $label . ' (' . $target . ')">';  };
        -    };
        -
        -sub MakeURLLink #(target, text)
        -    {
        -    my ($self, $target, $text) = @_;
        -    return '<url target="' . $target . '" name="' . $text . '">';
        -    };
        -
        -sub MakeEMailLink #(target, text)
        -    {
        -    my ($self, $target, $text) = @_;
        -    return '<email target="' . $target . '" name="' . $text . '">';
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Parser/Native.pm b/vendor/naturaldocs/Modules/NaturalDocs/Parser/Native.pm
        deleted file mode 100644
        index 39d8663b0..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Parser/Native.pm
        +++ /dev/null
        @@ -1,1073 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Parser::Native
        -#
        -###############################################################################
        -#
        -#   A package that converts comments from Natural Docs' native format into <NaturalDocs::Parser::ParsedTopic> objects.
        -#   Unlike most second-level packages, these are packages and not object classes.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Parser::Native;
        -
        -
        -###############################################################################
        -# Group: Variables
        -
        -
        -# Return values of TagType().  Not documented here.
        -use constant POSSIBLE_OPENING_TAG => 1;
        -use constant POSSIBLE_CLOSING_TAG => 2;
        -use constant NOT_A_TAG => 3;
        -
        -
        -#
        -#   var: package
        -#
        -#   A <SymbolString> representing the package normal topics will be a part of at the current point in the file.  This is a package variable
        -#   because it needs to be reserved between function calls.
        -#
        -my $package;
        -
        -#
        -#   hash: functionListIgnoredHeadings
        -#
        -#   An existence hash of all the headings that prevent the parser from creating function list symbols.  Whenever one of
        -#   these headings are used in a function list topic, symbols are not created from definition lists until the next heading.  The keys
        -#   are in all lowercase.
        -#
        -my %functionListIgnoredHeadings = ( 'parameters' => 1,
        -                                                       'parameter' => 1,
        -                                                       'params' => 1,
        -                                                       'param' => 1,
        -                                                       'arguments' => 1,
        -                                                       'argument' => 1,
        -                                                       'args' => 1,
        -                                                       'arg' => 1 );
        -
        -
        -###############################################################################
        -# Group: Interface Functions
        -
        -
        -#
        -#   Function: Start
        -#
        -#   This will be called whenever a file is about to be parsed.  It allows the package to reset its internal state.
        -#
        -sub Start
        -    {
        -    my ($self) = @_;
        -    $package = undef;
        -    };
        -
        -
        -#
        -#   Function: IsMine
        -#
        -#   Examines the comment and returns whether it is *definitely* Natural Docs content, i.e. it is owned by this package.  Note
        -#   that a comment can fail this function and still be interpreted as a Natural Docs content, for example a JavaDoc-styled comment
        -#   that doesn't have header lines but no JavaDoc tags either.
        -#
        -#   Parameters:
        -#
        -#       commentLines - An arrayref of the comment lines.  Must have been run through <NaturalDocs::Parser->CleanComment()>.
        -#       isJavaDoc - Whether the comment was JavaDoc-styled.
        -#
        -#   Returns:
        -#
        -#       Whether the comment is *definitely* Natural Docs content.
        -#
        -sub IsMine #(string[] commentLines, bool isJavaDoc)
        -    {
        -    my ($self, $commentLines, $isJavaDoc) = @_;
        -
        -    # Skip to the first line with content.
        -    my $line = 0;
        -
        -    while ($line < scalar @$commentLines && !length $commentLines->[$line])
        -        {  $line++;  };
        -
        -    return $self->ParseHeaderLine($commentLines->[$line]);
        -    };
        -
        -
        -
        -#
        -#   Function: ParseComment
        -#
        -#   This will be called whenever a comment capable of containing Natural Docs content is found.
        -#
        -#   Parameters:
        -#
        -#       commentLines - An arrayref of the comment lines.  Must have been run through <NaturalDocs::Parser->CleanComment()>.
        -#                               *The original memory will be changed.*
        -#       isJavaDoc - Whether the comment is JavaDoc styled.
        -#       lineNumber - The line number of the first of the comment lines.
        -#       parsedTopics - A reference to the array where any new <NaturalDocs::Parser::ParsedTopics> should be placed.
        -#
        -#   Returns:
        -#
        -#       The number of parsed topics added to the array, or zero if none.
        -#
        -sub ParseComment #(commentLines, isJavaDoc, lineNumber, parsedTopics)
        -    {
        -    my ($self, $commentLines, $isJavaDoc, $lineNumber, $parsedTopics) = @_;
        -
        -    my $topicCount = 0;
        -    my $prevLineBlank = 1;
        -    my $inCodeSection = 0;
        -
        -    my ($type, $scope, $isPlural, $title, $symbol);
        -    #my $package;  # package variable.
        -    my ($newKeyword, $newTitle);
        -
        -    my $index = 0;
        -
        -    my $bodyStart = 0;
        -    my $bodyEnd = 0;  # Not inclusive.
        -
        -    while ($index < scalar @$commentLines)
        -        {
        -        # Everything but leading whitespace was removed beforehand.
        -
        -        # If we're in a code section...
        -        if ($inCodeSection)
        -            {
        -            if ($commentLines->[$index] =~ /^ *\( *(?:end|finish|done)(?: +(?:table|code|example|diagram))? *\)$/i)
        -                {  $inCodeSection = undef;  };
        -
        -            $prevLineBlank = 0;
        -            $bodyEnd++;
        -            }
        -
        -        # If the line is empty...
        -        elsif (!length($commentLines->[$index]))
        -            {
        -            $prevLineBlank = 1;
        -
        -            if ($topicCount)
        -                {  $bodyEnd++;  };
        -            }
        -
        -        # If the line has a recognized header and the previous line is blank...
        -        elsif ($prevLineBlank && (($newKeyword, $newTitle) = $self->ParseHeaderLine($commentLines->[$index])) )
        -            {
        -            # Process the previous one, if any.
        -
        -            if ($topicCount)
        -                {
        -                if ($scope == ::SCOPE_START() || $scope == ::SCOPE_END())
        -                    {  $package = undef;  };
        -
        -                my $body = $self->FormatBody($commentLines, $bodyStart, $bodyEnd, $type, $isPlural);
        -                my $newTopic = $self->MakeParsedTopic($type, $title, $package, $body, $lineNumber + $bodyStart - 1, $isPlural);
        -                push @$parsedTopics, $newTopic;
        -
        -                $package = $newTopic->Package();
        -                };
        -
        -            $title = $newTitle;
        -
        -            my $typeInfo;
        -            ($type, $typeInfo, $isPlural) = NaturalDocs::Topics->KeywordInfo($newKeyword);
        -            $scope = $typeInfo->Scope();
        -
        -            $bodyStart = $index + 1;
        -            $bodyEnd = $index + 1;
        -
        -            $topicCount++;
        -
        -            $prevLineBlank = 0;
        -            }
        -
        -        # If we're on a non-empty, non-header line of a JavaDoc-styled comment and we haven't started a topic yet...
        -        elsif ($isJavaDoc && !$topicCount)
        -            {
        -            $type = undef;
        -            $scope = ::SCOPE_NORMAL();  # The scope repair and topic merging processes will handle if this is a class topic.
        -            $isPlural = undef;
        -            $title = undef;
        -            $symbol = undef;
        -
        -            $bodyStart = $index;
        -            $bodyEnd = $index + 1;
        -
        -            $topicCount++;
        -
        -            $prevLineBlank = undef;
        -            }
        -
        -        # If we're on a normal content line within a topic
        -        elsif ($topicCount)
        -            {
        -            $prevLineBlank = 0;
        -            $bodyEnd++;
        -
        -            if ($commentLines->[$index] =~ /^ *\( *(?:(?:start|begin)? +)?(?:table|code|example|diagram) *\)$/i)
        -                {  $inCodeSection = 1;  };
        -            };
        -
        -
        -        $index++;
        -        };
        -
        -
        -    # Last one, if any.  This is the only one that gets the prototypes.
        -    if ($topicCount)
        -        {
        -        if ($scope == ::SCOPE_START() || $scope == ::SCOPE_END())
        -            {  $package = undef;  };
        -
        -        my $body = $self->FormatBody($commentLines, $bodyStart, $bodyEnd, $type, $isPlural);
        -        my $newTopic = $self->MakeParsedTopic($type, $title, $package, $body, $lineNumber + $bodyStart - 1, $isPlural);
        -        push @$parsedTopics, $newTopic;
        -        $topicCount++;
        -
        -        $package = $newTopic->Package();
        -        };
        -
        -    return $topicCount;
        -    };
        -
        -
        -#
        -#   Function: ParseHeaderLine
        -#
        -#   If the passed line is a topic header, returns the array ( keyword, title ).  Otherwise returns an empty array.
        -#
        -sub ParseHeaderLine #(line)
        -    {
        -    my ($self, $line) = @_;
        -
        -    if ($line =~ /^ *([a-z0-9 ]*[a-z0-9]): +(.*)$/i)
        -        {
        -        my ($keyword, $title) = ($1, $2);
        -
        -        # We need to do it this way because if you do "if (ND:T->KeywordInfo($keyword)" and the last element of the array it
        -        # returns is false, the statement is false.  That is really retarded, but there it is.
        -        my ($type, undef, undef) = NaturalDocs::Topics->KeywordInfo($keyword);
        -
        -        if ($type)
        -            {  return ($keyword, $title);  }
        -        else
        -            {  return ( );  };
        -        }
        -    else
        -        {  return ( );  };
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -
        -#
        -#   Function: MakeParsedTopic
        -#
        -#   Creates a <NaturalDocs::Parser::ParsedTopic> object for the passed parameters.  Scope is gotten from
        -#   the package variable <package> instead of from the parameters.  The summary is generated from the body.
        -#
        -#   Parameters:
        -#
        -#       type         - The <TopicType>.  May be undef for headerless topics.
        -#       title          - The title of the topic.  May be undef for headerless topics.
        -#       package    - The package <SymbolString> the topic appears in.
        -#       body        - The topic's body in <NDMarkup>.
        -#       lineNumber - The topic's line number.
        -#       isList         - Whether the topic is a list.
        -#
        -#   Returns:
        -#
        -#       The <NaturalDocs::Parser::ParsedTopic> object.
        -#
        -sub MakeParsedTopic #(type, title, package, body, lineNumber, isList)
        -    {
        -    my ($self, $type, $title, $package, $body, $lineNumber, $isList) = @_;
        -
        -    my $summary;
        -
        -    if (defined $body)
        -        {  $summary = NaturalDocs::Parser->GetSummaryFromBody($body);  };
        -
        -    return NaturalDocs::Parser::ParsedTopic->New($type, $title, $package, undef, undef, $summary,
        -                                                                         $body, $lineNumber, $isList);
        -    };
        -
        -
        -#
        -#    Function: FormatBody
        -#
        -#    Converts the section body to <NDMarkup>.
        -#
        -#    Parameters:
        -#
        -#       commentLines - The arrayref of comment lines.
        -#       startingIndex  - The starting index of the body to format.
        -#       endingIndex   - The ending index of the body to format, *not* inclusive.
        -#       type               - The type of the section.  May be undef for headerless comments.
        -#       isList              - Whether it's a list topic.
        -#
        -#    Returns:
        -#
        -#        The body formatted in <NDMarkup>.
        -#
        -sub FormatBody #(commentLines, startingIndex, endingIndex, type, isList)
        -    {
        -    my ($self, $commentLines, $startingIndex, $endingIndex, $type, $isList) = @_;
        -
        -    use constant TAG_NONE => 1;
        -    use constant TAG_PARAGRAPH => 2;
        -    use constant TAG_BULLETLIST => 3;
        -    use constant TAG_DESCRIPTIONLIST => 4;
        -    use constant TAG_HEADING => 5;
        -    use constant TAG_PREFIXCODE => 6;
        -    use constant TAG_TAGCODE => 7;
        -
        -    my %tagEnders = ( TAG_NONE() => '',
        -                                 TAG_PARAGRAPH() => '</p>',
        -                                 TAG_BULLETLIST() => '</li></ul>',
        -                                 TAG_DESCRIPTIONLIST() => '</dd></dl>',
        -                                 TAG_HEADING() => '</h>',
        -                                 TAG_PREFIXCODE() => '</code>',
        -                                 TAG_TAGCODE() => '</code>' );
        -
        -    my $topLevelTag = TAG_NONE;
        -
        -    my $output;
        -    my $textBlock;
        -    my $prevLineBlank = 1;
        -
        -    my $codeBlock;
        -    my $removedCodeSpaces;
        -
        -    my $ignoreListSymbols;
        -
        -    my $index = $startingIndex;
        -
        -    while ($index < $endingIndex)
        -        {
        -        # If we're in a tagged code section...
        -        if ($topLevelTag == TAG_TAGCODE)
        -            {
        -            if ($commentLines->[$index] =~ /^ *\( *(?:end|finish|done)(?: +(?:table|code|example|diagram))? *\)$/i)
        -                {
        -                $codeBlock =~ s/\n+$//;
        -                $output .= NaturalDocs::NDMarkup->ConvertAmpChars($codeBlock) . '</code>';
        -                $codeBlock = undef;
        -                $topLevelTag = TAG_NONE;
        -                $prevLineBlank = undef;
        -                }
        -            else
        -                {
        -                $self->AddToCodeBlock($commentLines->[$index], \$codeBlock, \$removedCodeSpaces);
        -                };
        -            }
        -
        -        # If the line starts with a code designator...
        -        elsif ($commentLines->[$index] =~ /^ *[>:|](.*)$/)
        -            {
        -            my $code = $1;
        -
        -            if ($topLevelTag == TAG_PREFIXCODE)
        -                {
        -                $self->AddToCodeBlock($code, \$codeBlock, \$removedCodeSpaces);
        -                }
        -            else # $topLevelTag != TAG_PREFIXCODE
        -                {
        -                if (defined $textBlock)
        -                    {
        -                    $output .= $self->RichFormatTextBlock($textBlock) . $tagEnders{$topLevelTag};
        -                    $textBlock = undef;
        -                    };
        -
        -                $topLevelTag = TAG_PREFIXCODE;
        -                $output .= '<code type="anonymous">';
        -                $self->AddToCodeBlock($code, \$codeBlock, \$removedCodeSpaces);
        -                };
        -            }
        -
        -        # If we're not in either code style...
        -        else
        -            {
        -            # Strip any leading whitespace.
        -            $commentLines->[$index] =~ s/^ +//;
        -
        -            # If we were in a prefixed code section...
        -            if ($topLevelTag == TAG_PREFIXCODE)
        -                {
        -                $codeBlock =~ s/\n+$//;
        -                $output .= NaturalDocs::NDMarkup->ConvertAmpChars($codeBlock) . '</code>';
        -                $codeBlock = undef;
        -                $topLevelTag = TAG_NONE;
        -                $prevLineBlank = undef;
        -                };
        -
        -
        -            # If the line is blank...
        -            if (!length($commentLines->[$index]))
        -                {
        -                # End a paragraph.  Everything else ignores it for now.
        -                if ($topLevelTag == TAG_PARAGRAPH)
        -                    {
        -                    $output .= $self->RichFormatTextBlock($textBlock) . '</p>';
        -                    $textBlock = undef;
        -                    $topLevelTag = TAG_NONE;
        -                    };
        -
        -                $prevLineBlank = 1;
        -                }
        -
        -            # If the line starts with a bullet...
        -            elsif ($commentLines->[$index] =~ /^[-\*o+] +([^ ].*)$/ &&
        -                    substr($1, 0, 2) ne '- ')  # Make sure "o - Something" is a definition, not a bullet.
        -                {
        -                my $bulletedText = $1;
        -
        -                if (defined $textBlock)
        -                    {  $output .= $self->RichFormatTextBlock($textBlock);  };
        -
        -                if ($topLevelTag == TAG_BULLETLIST)
        -                    {
        -                    $output .= '</li><li>';
        -                    }
        -                else #($topLevelTag != TAG_BULLETLIST)
        -                    {
        -                    $output .= $tagEnders{$topLevelTag} . '<ul><li>';
        -                    $topLevelTag = TAG_BULLETLIST;
        -                    };
        -
        -                $textBlock = $bulletedText;
        -
        -                $prevLineBlank = undef;
        -                }
        -
        -            # If the line looks like a description list entry...
        -            elsif ($commentLines->[$index] =~ /^(.+?) +- +([^ ].*)$/ && $topLevelTag != TAG_PARAGRAPH)
        -                {
        -                my $entry = $1;
        -                my $description = $2;
        -
        -                if (defined $textBlock)
        -                    {  $output .= $self->RichFormatTextBlock($textBlock);  };
        -
        -                if ($topLevelTag == TAG_DESCRIPTIONLIST)
        -                    {
        -                    $output .= '</dd>';
        -                    }
        -                else #($topLevelTag != TAG_DESCRIPTIONLIST)
        -                    {
        -                    $output .= $tagEnders{$topLevelTag} . '<dl>';
        -                    $topLevelTag = TAG_DESCRIPTIONLIST;
        -                    };
        -
        -                if (($isList && !$ignoreListSymbols) || $type eq ::TOPIC_ENUMERATION())
        -                    {
        -                    $output .= '<ds>' . NaturalDocs::NDMarkup->ConvertAmpChars($entry) . '</ds><dd>';
        -                    }
        -                else
        -                    {
        -                    $output .= '<de>' . NaturalDocs::NDMarkup->ConvertAmpChars($entry) . '</de><dd>';
        -                    };
        -
        -                $textBlock = $description;
        -
        -                $prevLineBlank = undef;
        -                }
        -
        -            # If the line could be a header...
        -            elsif ($prevLineBlank && $commentLines->[$index] =~ /^(.*)([^ ]):$/)
        -                {
        -                my $headerText = $1 . $2;
        -
        -                if (defined $textBlock)
        -                    {
        -                    $output .= $self->RichFormatTextBlock($textBlock);
        -                    $textBlock = undef;
        -                    }
        -
        -                $output .= $tagEnders{$topLevelTag};
        -                $topLevelTag = TAG_NONE;
        -
        -                $output .= '<h>' . $self->RichFormatTextBlock($headerText) . '</h>';
        -
        -                if ($type eq ::TOPIC_FUNCTION() && $isList)
        -                    {
        -                    $ignoreListSymbols = exists $functionListIgnoredHeadings{lc($headerText)};
        -                    };
        -
        -                $prevLineBlank = undef;
        -                }
        -
        -            # If the line looks like a code tag...
        -            elsif ($commentLines->[$index] =~ /^\( *(?:(?:start|begin)? +)?(table|code|example|diagram) *\)$/i)
        -                {
        -				my $codeType = lc($1);
        -
        -                if (defined $textBlock)
        -                    {
        -                    $output .= $self->RichFormatTextBlock($textBlock);
        -                    $textBlock = undef;
        -                    };
        -
        -                if ($codeType eq 'example')
        -                	{  $codeType = 'anonymous';  }
        -                elsif ($codeType eq 'table' || $codeType eq 'diagram')
        -                	{  $codeType = 'text';  }
        -                # else leave it 'code'
        -
        -                $output .= $tagEnders{$topLevelTag} . '<code type="' . $codeType . '">';
        -                $topLevelTag = TAG_TAGCODE;
        -                }
        -
        -            # If the line looks like an inline image...
        -            elsif ($commentLines->[$index] =~ /^(\( *see +)([^\)]+?)( *\))$/i)
        -                {
        -                if (defined $textBlock)
        -                    {
        -                    $output .= $self->RichFormatTextBlock($textBlock);
        -                    $textBlock = undef;
        -                    };
        -
        -                $output .= $tagEnders{$topLevelTag};
        -                $topLevelTag = TAG_NONE;
        -
        -                $output .= '<img mode="inline" target="' . NaturalDocs::NDMarkup->ConvertAmpChars($2) . '" '
        -                                . 'original="' . NaturalDocs::NDMarkup->ConvertAmpChars($1 . $2 . $3) . '">';
        -
        -                $prevLineBlank = undef;
        -                }
        -
        -            # If the line isn't any of those, we consider it normal text.
        -            else
        -                {
        -                # A blank line followed by normal text ends lists.  We don't handle this when we detect if the line's blank because
        -                # we don't want blank lines between list items to break the list.
        -                if ($prevLineBlank && ($topLevelTag == TAG_BULLETLIST || $topLevelTag == TAG_DESCRIPTIONLIST))
        -                    {
        -                    $output .= $self->RichFormatTextBlock($textBlock) . $tagEnders{$topLevelTag} . '<p>';
        -
        -                    $topLevelTag = TAG_PARAGRAPH;
        -                    $textBlock = undef;
        -                    }
        -
        -                elsif ($topLevelTag == TAG_NONE)
        -                    {
        -                    $output .= '<p>';
        -                    $topLevelTag = TAG_PARAGRAPH;
        -                    # textBlock will already be undef.
        -                    };
        -
        -                if (defined $textBlock)
        -                    {  $textBlock .= ' ';  };
        -
        -                $textBlock .= $commentLines->[$index];
        -
        -                $prevLineBlank = undef;
        -                };
        -            };
        -
        -        $index++;
        -        };
        -
        -    # Clean up anything left dangling.
        -    if (defined $textBlock)
        -        {
        -        $output .= $self->RichFormatTextBlock($textBlock) . $tagEnders{$topLevelTag};
        -        }
        -    elsif (defined $codeBlock)
        -        {
        -        $codeBlock =~ s/\n+$//;
        -        $output .= NaturalDocs::NDMarkup->ConvertAmpChars($codeBlock) . '</code>';
        -        };
        -
        -    return $output;
        -    };
        -
        -
        -#
        -#   Function: AddToCodeBlock
        -#
        -#   Adds a line of text to a code block, handling all the indentation processing required.
        -#
        -#   Parameters:
        -#
        -#       line - The line of text to add.
        -#       codeBlockRef - A reference to the code block to add it to.
        -#       removedSpacesRef - A reference to a variable to hold the number of spaces removed.  It needs to be stored between calls.
        -#                                      It will reset itself automatically when the code block codeBlockRef points to is undef.
        -#
        -sub AddToCodeBlock #(line, codeBlockRef, removedSpacesRef)
        -    {
        -    my ($self, $line, $codeBlockRef, $removedSpacesRef) = @_;
        -
        -    $line =~ /^( *)(.*)$/;
        -    my ($spaces, $code) = ($1, $2);
        -
        -    if (!defined $$codeBlockRef)
        -        {
        -        if (length($code))
        -            {
        -            $$codeBlockRef = $code . "\n";
        -            $$removedSpacesRef = length($spaces);
        -            };
        -        # else ignore leading line breaks.
        -        }
        -
        -    elsif (length $code)
        -        {
        -        # Make sure we have the minimum amount of spaces to the left possible.
        -        if (length($spaces) != $$removedSpacesRef)
        -            {
        -            my $spaceDifference = abs( length($spaces) - $$removedSpacesRef );
        -            my $spacesToAdd = ' ' x $spaceDifference;
        -
        -            if (length($spaces) > $$removedSpacesRef)
        -                {
        -                $$codeBlockRef .= $spacesToAdd;
        -                }
        -            else
        -                {
        -                $$codeBlockRef =~ s/^(.)/$spacesToAdd . $1/gme;
        -                $$removedSpacesRef = length($spaces);
        -                };
        -            };
        -
        -        $$codeBlockRef .= $code . "\n";
        -        }
        -
        -    else # (!length $code)
        -        {
        -        $$codeBlockRef .= "\n";
        -        };
        -    };
        -
        -
        -#
        -#   Function: RichFormatTextBlock
        -#
        -#   Applies rich <NDMarkup> formatting to a chunk of text.  This includes both amp chars, formatting tags, and link tags.
        -#
        -#   Parameters:
        -#
        -#       text - The block of text to format.
        -#
        -#   Returns:
        -#
        -#       The formatted text block.
        -#
        -sub RichFormatTextBlock #(text)
        -    {
        -    my ($self, $text) = @_;
        -    my $output;
        -
        -
        -    # First find bare urls, e-mail addresses, and images.  We have to do this before the split because they may contain underscores
        -    # or asterisks.  We have to mark the tags with \x1E and \x1F so they don't get confused with angle brackets from the comment.
        -    # We can't convert the amp chars beforehand because we need lookbehinds in the regexps below and they need to be
        -    # constant length.  Sucks, huh?
        -
        -    $text =~ s{
        -                       # The previous character can't be an alphanumeric or an opening angle bracket.
        -                       (?<!  [a-z0-9<]  )
        -
        -                       # Optional mailto:.  Ignored in output.
        -                       (?:mailto\:)?
        -
        -                       # Begin capture
        -                       (
        -
        -                       # The user portion.  Alphanumeric and - _.  Dots can appear between, but not at the edges or more than
        -                       # one in a row.
        -                       (?:  [a-z0-9\-_]+  \.  )*   [a-z0-9\-_]+
        -
        -                       @
        -
        -                       # The domain.  Alphanumeric and -.  Dots same as above, however, there must be at least two sections
        -                       # and the last one must be two to four alphanumeric characters (.com, .uk, .info, .203 for IP addresses)
        -                       (?:  [a-z0-9\-]+  \.  )+  [a-z]{2,4}
        -
        -                       # End capture.
        -                       )
        -
        -                       # The next character can't be an alphanumeric, which should prevent .abcde from matching the two to
        -                       # four character requirement, or a closing angle bracket.
        -                       (?!  [a-z0-9>]  )
        -
        -                       }
        -
        -                       {"\x1E" . 'email target="' . NaturalDocs::NDMarkup->ConvertAmpChars($1) . '" '
        -                       . 'name="' . NaturalDocs::NDMarkup->ConvertAmpChars($1) . '"' . "\x1F"}igxe;
        -
        -    $text =~ s{
        -                       # The previous character can't be an alphanumeric or an opening angle bracket.
        -                       (?<!  [a-z0-9<]  )
        -
        -                       # Begin capture.
        -                       (
        -
        -                       # URL must start with one of the acceptable protocols.
        -                       (?:http|https|ftp|news|file)\:
        -
        -                       # The acceptable URL characters as far as I know.
        -                       [a-z0-9\-\=\~\@\#\%\&\_\+\/\;\:\?\*\.\,]*
        -
        -                       # The URL characters minus period and comma.  If it ends on them, they're probably intended as
        -                       # punctuation.
        -                       [a-z0-9\-\=\~\@\#\%\&\_\+\/\;\:\?\*]
        -
        -                       # End capture.
        -                       )
        -
        -                       # The next character must not be an acceptable character or a closing angle bracket.  It must also not be a
        -					   # dot and then an acceptable character.  These will prevent the URL from ending early just to get a match.
        -                       (?!  \.?[a-z0-9\-\=\~\@\#\%\&\_\+\/\;\:\?\*\>]  )
        -
        -                       }
        -
        -                       {"\x1E" . 'url target="' . NaturalDocs::NDMarkup->ConvertAmpChars($1) . '" '
        -                       . 'name="' . NaturalDocs::NDMarkup->ConvertAmpChars($1) . '"' . "\x1F"}igxe;
        -
        -
        -    # Find image links.  Inline images should already be pulled out by now.
        -
        -    $text =~ s{(\( *see +)([^\)\<\>]+?)( *\))}
        -                      {"\x1E" . 'img mode="link" target="' . NaturalDocs::NDMarkup->ConvertAmpChars($2) . '" '
        -                        . 'original="' . NaturalDocs::NDMarkup->ConvertAmpChars($1 . $2 . $3) . '"' . "\x1F"}gie;
        -
        -
        -
        -    # Split the text from the potential tags.
        -
        -    my @tempTextBlocks = split(/([\*_<>\x1E\x1F])/, $text);
        -
        -    # Since the symbols are considered dividers, empty strings could appear between two in a row or at the beginning/end of the
        -    # array.  This could seriously screw up TagType(), so we need to get rid of them.
        -    my @textBlocks;
        -
        -    while (scalar @tempTextBlocks)
        -        {
        -        my $tempTextBlock = shift @tempTextBlocks;
        -
        -        if (length $tempTextBlock)
        -            {  push @textBlocks, $tempTextBlock;  };
        -        };
        -
        -
        -    my $bold;
        -    my $underline;
        -    my $underlineHasWhitespace;
        -
        -    my $index = 0;
        -
        -    while ($index < scalar @textBlocks)
        -        {
        -        if ($textBlocks[$index] eq "\x1E")
        -            {
        -            $output .= '<';
        -            $index++;
        -
        -            while ($textBlocks[$index] ne "\x1F")
        -                {
        -                $output .= $textBlocks[$index];
        -                $index++;
        -                };
        -
        -            $output .= '>';
        -            }
        -
        -        elsif ($textBlocks[$index] eq '<' && $self->TagType(\@textBlocks, $index) == POSSIBLE_OPENING_TAG)
        -            {
        -            my $endingIndex = $self->ClosingTag(\@textBlocks, $index, undef);
        -
        -            if ($endingIndex != -1)
        -                {
        -                my $linkText;
        -                $index++;
        -
        -                while ($index < $endingIndex)
        -                    {
        -                    $linkText .= $textBlocks[$index];
        -                    $index++;
        -                    };
        -                # Index will be incremented again at the end of the loop.
        -
        -                $linkText = NaturalDocs::NDMarkup->ConvertAmpChars($linkText);
        -
        -                if ($linkText =~ /^(?:mailto\:)?((?:[a-z0-9\-_]+\.)*[a-z0-9\-_]+@(?:[a-z0-9\-]+\.)+[a-z]{2,4})$/i)
        -                    {  $output .= '<email target="' . $1 . '" name="' . $1 . '">';  }
        -                elsif ($linkText =~ /^(.+?) at (?:mailto\:)?((?:[a-z0-9\-_]+\.)*[a-z0-9\-_]+@(?:[a-z0-9\-]+\.)+[a-z]{2,4})$/i)
        -                    {  $output .= '<email target="' . $2 . '" name="' . $1 . '">';  }
        -                elsif ($linkText =~ /^(?:http|https|ftp|news|file)\:/i)
        -                    {  $output .= '<url target="' . $linkText . '" name="' . $linkText . '">';  }
        -                elsif ($linkText =~ /^(.+?) at ((?:http|https|ftp|news|file)\:.+)/i)
        -                    {  $output .= '<url target="' . $2 . '" name="' . $1 . '">';  }
        -                else
        -                    {  $output .= '<link target="' . $linkText . '" name="' . $linkText . '" original="&lt;' . $linkText . '&gt;">';  };
        -                }
        -
        -            else # it's not a link.
        -                {
        -                $output .= '&lt;';
        -                };
        -            }
        -
        -        elsif ($textBlocks[$index] eq '*')
        -            {
        -            my $tagType = $self->TagType(\@textBlocks, $index);
        -
        -            if ($tagType == POSSIBLE_OPENING_TAG && $self->ClosingTag(\@textBlocks, $index, undef) != -1)
        -                {
        -                # ClosingTag() makes sure tags aren't opened multiple times in a row.
        -                $bold = 1;
        -                $output .= '<b>';
        -                }
        -            elsif ($bold && $tagType == POSSIBLE_CLOSING_TAG)
        -                {
        -                $bold = undef;
        -                $output .= '</b>';
        -                }
        -            else
        -                {
        -                $output .= '*';
        -                };
        -            }
        -
        -        elsif ($textBlocks[$index] eq '_')
        -            {
        -            my $tagType = $self->TagType(\@textBlocks, $index);
        -
        -             if ($tagType == POSSIBLE_OPENING_TAG && $self->ClosingTag(\@textBlocks, $index, \$underlineHasWhitespace) != -1)
        -                {
        -                # ClosingTag() makes sure tags aren't opened multiple times in a row.
        -                $underline = 1;
        -                #underlineHasWhitespace is set by ClosingTag().
        -                $output .= '<u>';
        -                }
        -            elsif ($underline && $tagType == POSSIBLE_CLOSING_TAG)
        -                {
        -                $underline = undef;
        -                #underlineHasWhitespace will be reset by the next opening underline.
        -                $output .= '</u>';
        -                }
        -            elsif ($underline && !$underlineHasWhitespace)
        -                {
        -                # If there's no whitespace between underline tags, all underscores are replaced by spaces so
        -                # _some_underlined_text_ becomes <u>some underlined text</u>.  The standard _some underlined text_
        -                # will work too.
        -                $output .= ' ';
        -                }
        -            else
        -                {
        -                $output .= '_';
        -                };
        -            }
        -
        -        else # plain text or a > that isn't part of a link
        -            {
        -            $output .= NaturalDocs::NDMarkup->ConvertAmpChars($textBlocks[$index]);
        -           };
        -
        -        $index++;
        -        };
        -
        -    return $output;
        -    };
        -
        -
        -#
        -#   Function: TagType
        -#
        -#   Returns whether the tag is a possible opening or closing tag, or neither.  "Possible" because it doesn't check if an opening tag is
        -#   closed or a closing tag is opened, just whether the surrounding characters allow it to be a candidate for a tag.  For example, in
        -#   "A _B" the underscore is a possible opening underline tag, but in "A_B" it is not.  Support function for <RichFormatTextBlock()>.
        -#
        -#   Parameters:
        -#
        -#       textBlocks  - A reference to an array of text blocks.
        -#       index         - The index of the tag.
        -#
        -#   Returns:
        -#
        -#       POSSIBLE_OPENING_TAG, POSSIBLE_CLOSING_TAG, or NOT_A_TAG.
        -#
        -sub TagType #(textBlocks, index)
        -    {
        -    my ($self, $textBlocks, $index) = @_;
        -
        -
        -    # Possible opening tags
        -
        -    if ( ( $textBlocks->[$index] =~ /^[\*_<]$/ ) &&
        -
        -        # Before it must be whitespace, the beginning of the text, or ({["'-/*_.
        -        ( $index == 0 || $textBlocks->[$index-1] =~ /[\ \t\n\(\{\[\"\'\-\/\*\_]$/ ) &&
        -
        -        # Notes for 2.0: Include Spanish upside down ! and ? as well as opening quotes (66) and apostrophes (6).  Look into
        -        # Unicode character classes as well.
        -
        -        # After it must be non-whitespace.
        -        ( $index + 1 < scalar @$textBlocks && $textBlocks->[$index+1] !~ /^[\ \t\n]/) &&
        -
        -        # Make sure we don't accept <<, <=, <-, or *= as opening tags.
        -        ( $textBlocks->[$index] ne '<' || $textBlocks->[$index+1] !~ /^[<=-]/ ) &&
        -        ( $textBlocks->[$index] ne '*' || $textBlocks->[$index+1] !~ /^[\=\*]/ ) &&
        -
        -        # Make sure we don't accept * or _ before it unless it's <.
        -        ( $textBlocks->[$index] eq '<' || $index == 0 || $textBlocks->[$index-1] !~ /[\*\_]$/) )
        -        {
        -        return POSSIBLE_OPENING_TAG;
        -        }
        -
        -
        -    # Possible closing tags
        -
        -    elsif ( ( $textBlocks->[$index] =~ /^[\*_>]$/) &&
        -
        -            # After it must be whitespace, the end of the text, or )}].,!?"';:-/*_.
        -            ( $index + 1 == scalar @$textBlocks || $textBlocks->[$index+1] =~ /^[ \t\n\)\]\}\.\,\!\?\"\'\;\:\-\/\*\_]/ ||
        -              # Links also get plurals, like <link>s, <linx>es, <link>'s, and <links>'.
        -              ( $textBlocks->[$index] eq '>' && $textBlocks->[$index+1] =~ /^(?:es|s|\')/ ) ) &&
        -
        -            # Notes for 2.0: Include closing quotes (99) and apostrophes (9).  Look into Unicode character classes as well.
        -
        -            # Before it must be non-whitespace.
        -            ( $index != 0 && $textBlocks->[$index-1] !~ /[ \t\n]$/ ) &&
        -
        -            # Make sure we don't accept >>, ->, or => as closing tags.  >= is already taken care of.
        -            ( $textBlocks->[$index] ne '>' || $textBlocks->[$index-1] !~ /[>=-]$/ ) &&
        -
        -            # Make sure we don't accept * or _ after it unless it's >.
        -            ( $textBlocks->[$index] eq '>' || $textBlocks->[$index+1] !~ /[\*\_]$/) )
        -        {
        -        return POSSIBLE_CLOSING_TAG;
        -        }
        -
        -    else
        -        {
        -        return NOT_A_TAG;
        -        };
        -
        -    };
        -
        -
        -#
        -#   Function: ClosingTag
        -#
        -#   Returns whether a tag is closed or not, where it's closed if it is, and optionally whether there is any whitespace between the
        -#   tags.  Support function for <RichFormatTextBlock()>.
        -#
        -#   The results of this function are in full context, meaning that if it says a tag is closed, it can be interpreted as that tag in the
        -#   final output.  It takes into account any spoiling factors, like there being two opening tags in a row.
        -#
        -#   Parameters:
        -#
        -#       textBlocks             - A reference to an array of text blocks.
        -#       index                    - The index of the opening tag.
        -#       hasWhitespaceRef  - A reference to the variable that will hold whether there is whitespace between the tags or not.  If
        -#                                     undef, the function will not check.  If the tag is not closed, the variable will not be changed.
        -#
        -#   Returns:
        -#
        -#       If the tag is closed, it returns the index of the closing tag and puts whether there was whitespace between the tags in
        -#       hasWhitespaceRef if it was specified.  If the tag is not closed, it returns -1 and doesn't touch the variable pointed to by
        -#       hasWhitespaceRef.
        -#
        -sub ClosingTag #(textBlocks, index, hasWhitespace)
        -    {
        -    my ($self, $textBlocks, $index, $hasWhitespaceRef) = @_;
        -
        -    my $hasWhitespace;
        -    my $closingTag;
        -
        -    if ($textBlocks->[$index] eq '*' || $textBlocks->[$index] eq '_')
        -        {  $closingTag = $textBlocks->[$index];  }
        -    elsif ($textBlocks->[$index] eq '<')
        -        {  $closingTag = '>';  }
        -    else
        -        {  return -1;  };
        -
        -    my $beginningIndex = $index;
        -    $index++;
        -
        -    while ($index < scalar @$textBlocks)
        -        {
        -        if ($textBlocks->[$index] eq '<' && $self->TagType($textBlocks, $index) == POSSIBLE_OPENING_TAG)
        -            {
        -            # If we hit a < and we're checking whether a link is closed, it's not.  The first < becomes literal and the second one
        -            # becomes the new link opening.
        -            if ($closingTag eq '>')
        -                {
        -                return -1;
        -                }
        -
        -            # If we're not searching for the end of a link, we have to skip the link because formatting tags cannot appear within
        -            # them.  That's of course provided it's closed.
        -            else
        -                {
        -                my $linkHasWhitespace;
        -
        -                my $endIndex = $self->ClosingTag($textBlocks, $index,
        -                                                                    ($hasWhitespaceRef && !$hasWhitespace ? \$linkHasWhitespace : undef) );
        -
        -                if ($endIndex != -1)
        -                    {
        -                    if ($linkHasWhitespace)
        -                        {  $hasWhitespace = 1;  };
        -
        -                    # index will be incremented again at the end of the loop, which will bring us past the link's >.
        -                    $index = $endIndex;
        -                    };
        -                };
        -            }
        -
        -        elsif ($textBlocks->[$index] eq $closingTag)
        -            {
        -            my $tagType = $self->TagType($textBlocks, $index);
        -
        -            if ($tagType == POSSIBLE_CLOSING_TAG)
        -                {
        -                # There needs to be something between the tags for them to count.
        -                if ($index == $beginningIndex + 1)
        -                    {  return -1;  }
        -                else
        -                    {
        -                    # Success!
        -
        -                    if ($hasWhitespaceRef)
        -                        {  $$hasWhitespaceRef = $hasWhitespace;  };
        -
        -                    return $index;
        -                    };
        -                }
        -
        -            # If there are two opening tags of the same type, the first becomes literal and the next becomes part of a tag.
        -            elsif ($tagType == POSSIBLE_OPENING_TAG)
        -                {  return -1;  }
        -            }
        -
        -        elsif ($hasWhitespaceRef && !$hasWhitespace)
        -            {
        -            if ($textBlocks->[$index] =~ /[ \t\n]/)
        -                {  $hasWhitespace = 1;  };
        -            };
        -
        -        $index++;
        -        };
        -
        -    # Hit the end of the text blocks if we're here.
        -    return -1;
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Parser/ParsedTopic.pm b/vendor/naturaldocs/Modules/NaturalDocs/Parser/ParsedTopic.pm
        deleted file mode 100644
        index c4c2afd80..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Parser/ParsedTopic.pm
        +++ /dev/null
        @@ -1,254 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Parser::ParsedTopic
        -#
        -###############################################################################
        -#
        -#   A class for parsed topics of source files.  Also encompasses some of the <TopicType>-specific behavior.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Parser::ParsedTopic;
        -
        -
        -###############################################################################
        -# Group: Implementation
        -
        -#
        -#   Constants: Members
        -#
        -#   The object is a blessed arrayref with the following indexes.
        -#
        -#       TYPE           - The <TopicType>.
        -#       TITLE          - The title of the topic.
        -#       PACKAGE    - The package <SymbolString> the topic appears in, or undef if none.
        -#       USING         - An arrayref of additional package <SymbolStrings> available to the topic via "using" statements, or undef if
        -#                           none.
        -#       PROTOTYPE - The prototype, if it exists and is applicable.
        -#       SUMMARY    - The summary, if it exists.
        -#       BODY          - The body of the topic, formatted in <NDMarkup>.  Some topics may not have bodies, and if not, this
        -#                           will be undef.
        -#       LINE_NUMBER  - The line number the topic appears at in the file.
        -#       IS_LIST - Whether the topic is a list.
        -#
        -use NaturalDocs::DefineMembers 'TYPE', 'TITLE', 'PACKAGE', 'USING', 'PROTOTYPE', 'SUMMARY', 'BODY',
        -                                                 'LINE_NUMBER', 'IS_LIST';
        -# DEPENDENCY: New() depends on the order of these constants, and that this class is not inheriting any members.
        -
        -
        -#
        -#   Architecture: Title, Package, and Symbol Behavior
        -#
        -#   Title, package, and symbol behavior is a little awkward so it deserves some explanation.  Basically you set them according to
        -#   certain rules, but you get computed values that try to hide all the different scoping situations.
        -#
        -#   Normal Topics:
        -#
        -#       Set them to the title and package as they appear.  "Function" and "PkgA.PkgB" will return "Function" for the title,
        -#       "PkgA.PkgB" for the package, and "PkgA.PkgB.Function" for the symbol.
        -#
        -#       In the rare case that a title has a separator symbol it's treated as inadvertant, so "A vs. B" in "PkgA.PkgB" still returns just
        -#       "PkgA.PkgB" for the package even though if you got it from the symbol it can be seen as "PkgA.PkgB.A vs".
        -#
        -#   Scope Topics:
        -#
        -#       Set the title normally and leave the package undef.  So "PkgA.PkgB" and undef will return "PkgA.PkgB" for the title as well
        -#       as for the package and symbol.
        -#
        -#       The only time you should set the package is when you have full language support and they only documented the class with
        -#       a partial title.  So if you documented "PkgA.PkgB" with just "PkgB", you want to set the package to "PkgA".  This
        -#       will return "PkgB" as the title for presentation and will return "PkgA.PkgB" for the package and symbol, which is correct.
        -#
        -#   Always Global Topics:
        -#
        -#       Set the title and package normally, do not set the package to undef.  So "Global" and "PkgA.PkgB" will return "Global" as
        -#       the title, "PkgA.PkgB" as the package, and "Global" as the symbol.
        -#
        -#   Um, yeah...:
        -#
        -#       So does this suck?  Yes, yes it does.  But the suckiness is centralized here instead of having to be handled everywhere these
        -#       issues come into play.  Just realize there are a certain set of rules to follow when you *set* these variables, and the results
        -#       you see when you *get* them are computed rather than literal.
        -#
        -
        -
        -###############################################################################
        -# Group: Functions
        -
        -#
        -#   Function: New
        -#
        -#   Creates a new object.
        -#
        -#   Parameters:
        -#
        -#       type          - The <TopicType>.
        -#       title           - The title of the topic.
        -#       package    - The package <SymbolString> the topic appears in, or undef if none.
        -#       using         - An arrayref of additional package <SymbolStrings> available to the topic via "using" statements, or undef if
        -#                          none.
        -#       prototype   - The prototype, if it exists and is applicable.  Otherwise set to undef.
        -#       summary   - The summary of the topic, if any.
        -#       body          - The body of the topic, formatted in <NDMarkup>.  May be undef, as some topics may not have bodies.
        -#       lineNumber - The line number the topic appears at in the file.
        -#       isList          - Whether the topic is a list topic or not.
        -#
        -#   Returns:
        -#
        -#       The new object.
        -#
        -sub New #(type, title, package, using, prototype, summary, body, lineNumber, isList)
        -    {
        -    # DEPENDENCY: This depends on the order of the parameter list being the same as the constants, and that there are no
        -    # members inherited from a base class.
        -
        -    my $package = shift;
        -
        -    my $object = [ @_ ];
        -    bless $object, $package;
        -
        -    if (defined $object->[USING])
        -        {  $object->[USING] = [ @{$object->[USING]} ];  };
        -
        -    return $object;
        -    };
        -
        -
        -# Function: Type
        -# Returns the <TopicType>.
        -sub Type
        -    {  return $_[0]->[TYPE];  };
        -
        -# Function: SetType
        -# Replaces the <TopicType>.
        -sub SetType #(type)
        -    {  $_[0]->[TYPE] = $_[1];  };
        -
        -# Function: IsList
        -# Returns whether the topic is a list.
        -sub IsList
        -    {  return $_[0]->[IS_LIST];  };
        -
        -# Function: SetIsList
        -# Sets whether the topic is a list.
        -sub SetIsList
        -    {  $_[0]->[IS_LIST] = $_[1];  };
        -
        -# Function: Title
        -# Returns the title of the topic.
        -sub Title
        -    {  return $_[0]->[TITLE];  };
        -
        -# Function: SetTitle
        -# Replaces the topic title.
        -sub SetTitle #(title)
        -    {  $_[0]->[TITLE] = $_[1];  };
        -
        -#
        -#   Function: Symbol
        -#
        -#   Returns the <SymbolString> defined by the topic.  It is fully resolved and does _not_ need to be joined with <Package()>.
        -#
        -#   Type-Specific Behavior:
        -#
        -#       - If the <TopicType> is always global, the symbol will be generated from the title only.
        -#       - Everything else's symbols will be generated from the title and the package passed to <New()>.
        -#
        -sub Symbol
        -    {
        -    my ($self) = @_;
        -
        -    my $titleSymbol = NaturalDocs::SymbolString->FromText($self->[TITLE]);
        -
        -    if (NaturalDocs::Topics->TypeInfo($self->Type())->Scope() == ::SCOPE_ALWAYS_GLOBAL())
        -        {  return $titleSymbol;  }
        -    else
        -        {
        -        return NaturalDocs::SymbolString->Join( $self->[PACKAGE], $titleSymbol );
        -        };
        -    };
        -
        -
        -#
        -#   Function: Package
        -#
        -#   Returns the package <SymbolString> that the topic appears in.
        -#
        -#   Type-Specific Behavior:
        -#
        -#       - If the <TopicType> has scope, the package will be generated from both the title and the package passed to <New()>, not
        -#         just the package.
        -#       - If the <TopicType> is always global, the package will be the one passed to <New()>, even though it isn't part of it's
        -#         <Symbol()>.
        -#       - Everything else's package will be what was passed to <New()>, even if the title has separator symbols in it.
        -#
        -sub Package
        -    {
        -    my ($self) = @_;
        -
        -    # Headerless topics may not have a type yet.
        -    if ($self->Type() && NaturalDocs::Topics->TypeInfo($self->Type())->Scope() == ::SCOPE_START())
        -        {  return $self->Symbol();  }
        -    else
        -        {  return $self->[PACKAGE];  };
        -    };
        -
        -
        -# Function: SetPackage
        -# Replaces the package the topic appears in.  This will behave the same way as the package parameter in <New()>.  Later calls
        -# to <Package()> will still be generated according to its type-specific behavior.
        -sub SetPackage #(package)
        -    {  $_[0]->[PACKAGE] = $_[1];  };
        -
        -# Function: Using
        -# Returns an arrayref of additional scope <SymbolStrings> available to the topic via "using" statements, or undef if none.
        -sub Using
        -    {  return $_[0]->[USING];  };
        -
        -# Function: SetUsing
        -# Replaces the using arrayref of sope <SymbolStrings>.
        -sub SetUsing #(using)
        -    {  $_[0]->[USING] = $_[1];  };
        -
        -# Function: Prototype
        -# Returns the prototype if one is defined.  Will be undef otherwise.
        -sub Prototype
        -    {  return $_[0]->[PROTOTYPE];  };
        -
        -# Function: SetPrototype
        -# Replaces the function or variable prototype.
        -sub SetPrototype #(prototype)
        -    {  $_[0]->[PROTOTYPE] = $_[1];  };
        -
        -# Function: Summary
        -# Returns the topic summary, if it exists, formatted in <NDMarkup>.
        -sub Summary
        -    {  return $_[0]->[SUMMARY];  };
        -
        -# Function: Body
        -# Returns the topic's body, formatted in <NDMarkup>.  May be undef.
        -sub Body
        -    {  return $_[0]->[BODY];  };
        -
        -# Function: SetBody
        -# Replaces the topic's body, formatted in <NDMarkup>.  May be undef.
        -sub SetBody #(body)
        -    {
        -    my ($self, $body) = @_;
        -    $self->[BODY] = $body;
        -    };
        -
        -# Function: LineNumber
        -# Returns the line the topic appears at in the file.
        -sub LineNumber
        -    {  return $_[0]->[LINE_NUMBER];  };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Project.pm b/vendor/naturaldocs/Modules/NaturalDocs/Project.pm
        deleted file mode 100644
        index b62495fe1..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Project.pm
        +++ /dev/null
        @@ -1,1404 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Project
        -#
        -###############################################################################
        -#
        -#   A package that manages information about the files in the source tree, as well as the list of files that have to be parsed
        -#   and built.
        -#
        -#   Usage and Dependencies:
        -#
        -#       - All the <Config and Data File Functions> are available immediately, except for the status functions.
        -#
        -#       - <ReparseEverything()> and <RebuildEverything()> are available immediately, because they may need to be called
        -#         after <LoadConfigFileInfo()> but before <LoadSourceFileInfo()>.
        -#
        -#       - Prior to <LoadConfigFileInfo()>, <NaturalDocs::Settings> must be initialized.
        -#
        -#       - After <LoadConfigFileInfo()>, the status <Config and Data File Functions> are available as well.
        -#
        -#       - Prior to <LoadSourceFileInfo()>, <NaturalDocs::Settings> and <NaturalDocs::Languages> must be initialized.
        -#
        -#       - After <LoadSourceFileInfo()>, the rest of the <Source File Functions> are available.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use NaturalDocs::Project::SourceFile;
        -use NaturalDocs::Project::ImageFile;
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Project;
        -
        -
        -###############################################################################
        -# Group: File Handles
        -
        -#
        -#   handle: FH_FILEINFO
        -#
        -#   The file handle for the file information file, <FileInfo.nd>.
        -#
        -
        -#
        -#   handle: FH_CONFIGFILEINFO
        -#
        -#   The file handle for the config file information file, <ConfigFileInfo.nd>.
        -#
        -
        -#
        -#   handle: FH_IMAGEFILE
        -#
        -#   The file handle for determining the dimensions of image files.
        -#
        -
        -
        -
        -###############################################################################
        -# Group: Source File Variables
        -
        -
        -#
        -#   hash: supportedFiles
        -#
        -#   A hash of all the supported files in the input directory.  The keys are the <FileNames>, and the values are
        -#   <NaturalDocs::Project::SourceFile> objects.
        -#
        -my %supportedFiles;
        -
        -#
        -#   hash: filesToParse
        -#
        -#   An existence hash of all the <FileNames> that need to be parsed.
        -#
        -my %filesToParse;
        -
        -#
        -#   hash: filesToBuild
        -#
        -#   An existence hash of all the <FileNames> that need to be built.
        -#
        -my %filesToBuild;
        -
        -#
        -#   hash: filesToPurge
        -#
        -#   An existence hash of the <FileNames> that had Natural Docs content last time, but now either don't exist or no longer have
        -#   content.
        -#
        -my %filesToPurge;
        -
        -#
        -#   hash: unbuiltFilesWithContent
        -#
        -#   An existence hash of all the <FileNames> that have Natural Docs content but are not part of <filesToBuild>.
        -#
        -my %unbuiltFilesWithContent;
        -
        -
        -# bool: reparseEverything
        -# Whether all the source files need to be reparsed.
        -my $reparseEverything;
        -
        -# bool: rebuildEverything
        -# Whether all the source files need to be rebuilt.
        -my $rebuildEverything;
        -
        -# hash: mostUsedLanguage
        -# The name of the most used language.  Doesn't include text files.
        -my $mostUsedLanguage;
        -
        -
        -
        -###############################################################################
        -# Group: Configuration File Variables
        -
        -
        -#
        -#   hash: mainConfigFile
        -#
        -#   A hash mapping all the main configuration file names without paths to their <FileStatus>.  Prior to <LoadConfigFileInfo()>,
        -#   it serves as an existence hashref of the file names.
        -#
        -my %mainConfigFiles = ( 'Topics.txt' => 1, 'Languages.txt' => 1 );
        -
        -#
        -#   hash: userConfigFiles
        -#
        -#   A hash mapping all the user configuration file names without paths to their <FileStatus>.  Prior to <LoadConfigFileInfo()>,
        -#   it serves as an existence hashref of the file names.
        -#
        -my %userConfigFiles = ( 'Topics.txt' => 1, 'Languages.txt' => 1, 'Menu.txt' => 1 );
        -
        -
        -
        -
        -###############################################################################
        -# Group: Image File Variables
        -
        -
        -#
        -#   hash: imageFileExtensions
        -#
        -#   An existence hash of all the file extensions for images.  Extensions are in all lowercase.
        -#
        -my %imageFileExtensions = ( 'jpg' => 1, 'jpeg' => 1, 'gif' => 1, 'png' => 1, 'bmp' => 1 );
        -
        -
        -#
        -#   hash: imageFiles
        -#
        -#   A hash of all the image files in the project.  The keys are the <FileNames> and the values are
        -#   <NaturalDocs::Project::ImageFiles>.
        -#
        -my %imageFiles;
        -
        -
        -#
        -#   hash: imageFilesToUpdate
        -#
        -#   An existence hash of all the image <FileNames> that need to be updated, either because they changed or they're new to the
        -#   project.
        -#
        -my %imageFilesToUpdate;
        -
        -
        -#
        -#   hash: imageFilesToPurge
        -#
        -#   An existence hash of all the image <FileNames> that need to be purged, either because the files no longer exist or because
        -#   they are no longer used.
        -#
        -my %imageFilesToPurge;
        -
        -
        -#
        -#   hash: insensitiveImageFiles
        -#
        -#   A hash that maps all lowercase image <FileNames> to their proper case as it would appear in <imageFiles>.  Used for
        -#   case insensitivity, obviously.
        -#
        -#   You can't just use all lowercase in <imageFiles> because both Linux and HTTP are case sensitive, so the original case must
        -#   be preserved.  We also want to allow separate entries for files that differ based only on case, so it goes to <imageFiles> first
        -#   where they can be distinguished and here only if there's no match.  Ties are broken by whichever is lower with cmp, because
        -#   it has to resolve consistently on all runs of the program.
        -#
        -my %insensitiveImageFiles;
        -
        -
        -
        -###############################################################################
        -# Group: Files
        -
        -
        -#
        -#   File: FileInfo.nd
        -#
        -#   An index of the state of the files as of the last parse.  Used to determine if files were added, deleted, or changed.
        -#
        -#   Format:
        -#
        -#       The format is a text file.
        -#
        -#       > [VersionInt: app version]
        -#
        -#       The beginning of the file is the <VersionInt> it was generated with.
        -#
        -#       > [most used language name]
        -#
        -#       Next is the name of the most used language in the source tree.  Does not include text files.
        -#
        -#       Each following line is
        -#
        -#       > [file name] tab [last modification time] tab [has ND content (0 or 1)] tab [default menu title] \n
        -#
        -#   Revisions:
        -#
        -#       1.3:
        -#
        -#           - The line following the <VersionInt>, which was previously the last modification time of <Menu.txt>, was changed to
        -#             the name of the most used language.
        -#
        -#       1.16:
        -#
        -#           - File names are now absolute.  Prior to 1.16, they were relative to the input directory since only one was allowed.
        -#
        -#       1.14:
        -#
        -#           - The file was renamed from NaturalDocs.files to FileInfo.nd and moved into the Data subdirectory.
        -#
        -#       0.95:
        -#
        -#           - The file version was changed to match the program version.  Prior to 0.95, the version line was 1.  Test for "1" instead
        -#             of "1.0" to distinguish.
        -#
        -
        -
        -#
        -#   File: ConfigFileInfo.nd
        -#
        -#   An index of the state of the config files as of the last parse.
        -#
        -#   Format:
        -#
        -#       > [BINARY_FORMAT]
        -#       > [VersionInt: app version]
        -#
        -#       First is the standard <BINARY_FORMAT> <VersionInt> header.
        -#
        -#       > [UInt32: last modification time of menu]
        -#       > [UInt32: last modification of main topics file]
        -#       > [UInt32: last modification of user topics file]
        -#       > [UInt32: last modification of main languages file]
        -#       > [UInt32: last modification of user languages file]
        -#
        -#       Next are the last modification times of various configuration files as UInt32s in the standard Unix format.
        -#
        -#
        -#   Revisions:
        -#
        -#       1.3:
        -#
        -#           - The file was added to Natural Docs.  Previously the last modification of <Menu.txt> was stored in <FileInfo.nd>, and
        -#             <Topics.txt> and <Languages.txt> didn't exist.
        -#
        -
        -
        -#
        -#   File: ImageFileInfo.nd
        -#
        -#   An index of the state of the image files as of the last parse.
        -#
        -#   Format:
        -#
        -#       > [Standard Binary Header]
        -#
        -#       First is the standard binary file header as defined by <NaturalDocs::BinaryFile>.
        -#
        -#       > [AString16: file name or undef]
        -#       > [UInt32: last modification time]
        -#       > [UInt8: was used]
        -#
        -#       This section is repeated until the file name is null.  The last modification times are UInt32s in the standard Unix format.
        -#
        -#
        -#   Revisions:
        -#
        -#       1.4:
        -#
        -#           - The file was added to Natural Docs.
        -#
        -
        -
        -
        -###############################################################################
        -# Group: File Functions
        -
        -#
        -#   Function: LoadSourceFileInfo
        -#
        -#   Loads the project file from disk and compares it against the files in the input directory.  Project is loaded from
        -#   <FileInfo.nd>.  New and changed files will be added to <FilesToParse()>, and if they have content,
        -#   <FilesToBuild()>.
        -#
        -#   Will call <NaturalDocs::Languages->OnMostUsedLanguageKnown()> if <MostUsedLanguage()> changes.
        -#
        -#   Returns:
        -#
        -#       Returns whether the project was changed in any way.
        -#
        -sub LoadSourceFileInfo
        -    {
        -    my ($self) = @_;
        -
        -    $self->GetAllSupportedFiles();
        -    NaturalDocs::Languages->OnMostUsedLanguageKnown();
        -
        -    my $fileIsOkay;
        -    my $version;
        -    my $hasChanged;
        -    my $lineReader;
        -
        -    if (open(FH_FILEINFO, '<' . $self->DataFile('FileInfo.nd')))
        -        {
        -        $lineReader = NaturalDocs::LineReader->New(\*FH_FILEINFO);
        -
        -        # Check if the file is in the right format.
        -        $version = NaturalDocs::Version->FromString($lineReader->Get());
        -
        -        # The project file need to be rebuilt for 1.16.  The source files need to be reparsed and the output files rebuilt for 1.51.
        -        # We'll tolerate the difference between 1.16 and 1.3 in the loader.
        -
        -        if (NaturalDocs::Version->CheckFileFormat( $version, NaturalDocs::Version->FromString('1.16') ))
        -            {
        -            $fileIsOkay = 1;
        -
        -            if (!NaturalDocs::Version->CheckFileFormat( $version, NaturalDocs::Version->FromString('1.51') ))
        -                {
        -                $reparseEverything = 1;
        -                $rebuildEverything = 1;
        -                $hasChanged = 1;
        -                };
        -            }
        -        else
        -            {
        -            close(FH_FILEINFO);
        -            $hasChanged = 1;
        -            };
        -        };
        -
        -
        -    if ($fileIsOkay)
        -        {
        -        my %indexedFiles;
        -
        -
        -        my $line = $lineReader->Get();
        -
        -        # Prior to 1.3 it was the last modification time of Menu.txt, which we ignore and treat as though the most used language
        -        # changed.  Prior to 1.32 the settings didn't transfer over correctly to Menu.txt so we need to behave that way again.
        -        if ($version < NaturalDocs::Version->FromString('1.32') || lc($mostUsedLanguage) ne lc($line))
        -            {
        -            $reparseEverything = 1;
        -            NaturalDocs::SymbolTable->RebuildAllIndexes();
        -            };
        -
        -
        -        # Parse the rest of the file.
        -
        -        while ($line = $lineReader->Get())
        -            {
        -            my ($file, $modification, $hasContent, $menuTitle) = split(/\t/, $line, 4);
        -
        -            # If the file no longer exists...
        -            if (!exists $supportedFiles{$file})
        -                {
        -                if ($hasContent)
        -                    {  $filesToPurge{$file} = 1;  };
        -
        -                $hasChanged = 1;
        -                }
        -
        -            # If the file still exists...
        -            else
        -                {
        -                $indexedFiles{$file} = 1;
        -
        -                # If the file changed...
        -                if ($supportedFiles{$file}->LastModified() != $modification)
        -                    {
        -                    $supportedFiles{$file}->SetStatus(::FILE_CHANGED());
        -                    $filesToParse{$file} = 1;
        -
        -                    # If the file loses its content, this will be removed by SetHasContent().
        -                    if ($hasContent)
        -                        {  $filesToBuild{$file} = 1;  };
        -
        -                    $hasChanged = 1;
        -                    }
        -
        -                # If the file has not changed...
        -                else
        -                    {
        -                    my $status;
        -
        -                    if ($rebuildEverything && $hasContent)
        -                        {
        -                        $status = ::FILE_CHANGED();
        -
        -                        # If the file loses its content, this will be removed by SetHasContent().
        -                        $filesToBuild{$file} = 1;
        -                        $hasChanged = 1;
        -                        }
        -                    else
        -                        {
        -                        $status = ::FILE_SAME();
        -
        -                        if ($hasContent)
        -                            {  $unbuiltFilesWithContent{$file} = 1;  };
        -                        };
        -
        -                    if ($reparseEverything)
        -                        {
        -                        $status = ::FILE_CHANGED();
        -
        -                        $filesToParse{$file} = 1;
        -                        $hasChanged = 1;
        -                        };
        -
        -                    $supportedFiles{$file}->SetStatus($status);
        -                    };
        -
        -                $supportedFiles{$file}->SetHasContent($hasContent);
        -                $supportedFiles{$file}->SetDefaultMenuTitle($menuTitle);
        -                };
        -            };
        -
        -        close(FH_FILEINFO);
        -
        -
        -        # Check for added files.
        -
        -        if (scalar keys %supportedFiles > scalar keys %indexedFiles)
        -            {
        -            foreach my $file (keys %supportedFiles)
        -                {
        -                if (!exists $indexedFiles{$file})
        -                    {
        -                    $supportedFiles{$file}->SetStatus(::FILE_NEW());
        -                    $supportedFiles{$file}->SetDefaultMenuTitle($file);
        -                    $supportedFiles{$file}->SetHasContent(undef);
        -                    $filesToParse{$file} = 1;
        -                    # It will be added to filesToBuild if HasContent gets set to true when it's parsed.
        -                    $hasChanged = 1;
        -                    };
        -                };
        -            };
        -        }
        -
        -    # If something's wrong with FileInfo.nd, everything is new.
        -    else
        -        {
        -        foreach my $file (keys %supportedFiles)
        -            {
        -            $supportedFiles{$file}->SetStatus(::FILE_NEW());
        -            $supportedFiles{$file}->SetDefaultMenuTitle($file);
        -            $supportedFiles{$file}->SetHasContent(undef);
        -            $filesToParse{$file} = 1;
        -            # It will be added to filesToBuild if HasContent gets set to true when it's parsed.
        -            };
        -
        -        $hasChanged = 1;
        -        };
        -
        -
        -    # There are other side effects, so we need to call this.
        -    if ($rebuildEverything)
        -        {  $self->RebuildEverything();  };
        -
        -
        -    return $hasChanged;
        -    };
        -
        -
        -#
        -#   Function: SaveSourceFileInfo
        -#
        -#   Saves the source file info to disk.  Everything is saved in <FileInfo.nd>.
        -#
        -sub SaveSourceFileInfo
        -    {
        -    my ($self) = @_;
        -
        -    open(FH_FILEINFO, '>' . $self->DataFile('FileInfo.nd'))
        -        or die "Couldn't save project file " . $self->DataFile('FileInfo.nd') . "\n";
        -
        -    NaturalDocs::Version->ToTextFile(\*FH_FILEINFO, NaturalDocs::Settings->AppVersion());
        -
        -    print FH_FILEINFO $mostUsedLanguage . "\n";
        -
        -    while (my ($fileName, $file) = each %supportedFiles)
        -        {
        -        print FH_FILEINFO $fileName . "\t"
        -                              . $file->LastModified() . "\t"
        -                              . ($file->HasContent() || '0') . "\t"
        -                              . $file->DefaultMenuTitle() . "\n";
        -        };
        -
        -    close(FH_FILEINFO);
        -    };
        -
        -
        -#
        -#   Function: LoadConfigFileInfo
        -#
        -#   Loads the config file info from disk.
        -#
        -sub LoadConfigFileInfo
        -    {
        -    my ($self) = @_;
        -
        -    my $fileIsOkay;
        -    my $version;
        -    my $fileName = NaturalDocs::Project->DataFile('ConfigFileInfo.nd');
        -
        -    if (open(FH_CONFIGFILEINFO, '<' . $fileName))
        -        {
        -        # See if it's binary.
        -        binmode(FH_CONFIGFILEINFO);
        -
        -        my $firstChar;
        -        read(FH_CONFIGFILEINFO, $firstChar, 1);
        -
        -        if ($firstChar == ::BINARY_FORMAT())
        -            {
        -            $version = NaturalDocs::Version->FromBinaryFile(\*FH_CONFIGFILEINFO);
        -
        -            # It hasn't changed since being introduced.
        -
        -            if (NaturalDocs::Version->CheckFileFormat($version))
        -                {  $fileIsOkay = 1;  }
        -            else
        -                {  close(FH_CONFIGFILEINFO);  };
        -            }
        -
        -        else # it's not in binary
        -            {  close(FH_CONFIGFILEINFO);  };
        -        };
        -
        -    my @configFiles = ( $self->UserConfigFile('Menu.txt'), \$userConfigFiles{'Menu.txt'},
        -                                 $self->MainConfigFile('Topics.txt'), \$mainConfigFiles{'Topics.txt'},
        -                                 $self->UserConfigFile('Topics.txt'), \$userConfigFiles{'Topics.txt'},
        -                                 $self->MainConfigFile('Languages.txt'), \$mainConfigFiles{'Languages.txt'},
        -                                 $self->UserConfigFile('Languages.txt'), \$userConfigFiles{'Languages.txt'} );
        -
        -    if ($fileIsOkay)
        -        {
        -        my $raw;
        -
        -        read(FH_CONFIGFILEINFO, $raw, 20);
        -        my @configFileDates = unpack('NNNNN', $raw);
        -
        -        while (scalar @configFiles)
        -            {
        -            my $file = shift @configFiles;
        -            my $fileStatus = shift @configFiles;
        -            my $fileDate = shift @configFileDates;
        -
        -            if (-e $file)
        -                {
        -                if ($fileDate == (stat($file))[9])
        -                    {  $$fileStatus = ::FILE_SAME();  }
        -                else
        -                    {  $$fileStatus = ::FILE_CHANGED();  };
        -                }
        -            else
        -                {  $$fileStatus = ::FILE_DOESNTEXIST();  };
        -            };
        -
        -        close(FH_CONFIGFILEINFO);
        -        }
        -    else # !$fileIsOkay
        -        {
        -        while (scalar @configFiles)
        -            {
        -            my $file = shift @configFiles;
        -            my $fileStatus = shift @configFiles;
        -
        -            if (-e $file)
        -                {  $$fileStatus = ::FILE_CHANGED();  }
        -            else
        -                {  $$fileStatus = ::FILE_DOESNTEXIST();  };
        -            };
        -        };
        -
        -    if ($userConfigFiles{'Menu.txt'} == ::FILE_SAME() && $rebuildEverything)
        -        {  $userConfigFiles{'Menu.txt'} = ::FILE_CHANGED();  };
        -    };
        -
        -
        -#
        -#   Function: SaveConfigFileInfo
        -#
        -#   Saves the config file info to disk.  You *must* save all other config files first, such as <Menu.txt> and <Topics.txt>.
        -#
        -sub SaveConfigFileInfo
        -    {
        -    my ($self) = @_;
        -
        -    open (FH_CONFIGFILEINFO, '>' . NaturalDocs::Project->DataFile('ConfigFileInfo.nd'))
        -        or die "Couldn't save " . NaturalDocs::Project->DataFile('ConfigFileInfo.nd') . ".\n";
        -
        -    binmode(FH_CONFIGFILEINFO);
        -
        -    print FH_CONFIGFILEINFO '' . ::BINARY_FORMAT();
        -
        -    NaturalDocs::Version->ToBinaryFile(\*FH_CONFIGFILEINFO, NaturalDocs::Settings->AppVersion());
        -
        -    print FH_CONFIGFILEINFO pack('NNNNN', (stat($self->UserConfigFile('Menu.txt')))[9],
        -                                                                (stat($self->MainConfigFile('Topics.txt')))[9],
        -                                                                (stat($self->UserConfigFile('Topics.txt')))[9],
        -                                                                (stat($self->MainConfigFile('Languages.txt')))[9],
        -                                                                (stat($self->UserConfigFile('Languages.txt')))[9] );
        -
        -    close(FH_CONFIGFILEINFO);
        -    };
        -
        -
        -#
        -#   Function: LoadImageFileInfo
        -#
        -#   Loads the image file info from disk.
        -#
        -sub LoadImageFileInfo
        -    {
        -    my ($self) = @_;
        -
        -    my $version = NaturalDocs::BinaryFile->OpenForReading( NaturalDocs::Project->DataFile('ImageFileInfo.nd') );
        -    my $fileIsOkay;
        -
        -    if (defined $version)
        -        {
        -        # It hasn't changed since being introduced.
        -
        -        if (NaturalDocs::Version->CheckFileFormat($version))
        -            {  $fileIsOkay = 1;  }
        -        else
        -            {  NaturalDocs::BinaryFile->Close();  };
        -        };
        -
        -    if ($fileIsOkay)
        -        {
        -        # [AString16: file name or undef]
        -
        -        while (my $imageFile = NaturalDocs::BinaryFile->GetAString16())
        -            {
        -            # [UInt32: last modified]
        -            # [UInt8: was used]
        -
        -            my $lastModified = NaturalDocs::BinaryFile->GetUInt32();
        -            my $wasUsed = NaturalDocs::BinaryFile->GetUInt8();
        -
        -            my $imageFileObject = $imageFiles{$imageFile};
        -
        -            # If there's an image file in ImageFileInfo.nd that no longer exists...
        -            if (!$imageFileObject)
        -                {
        -                $imageFileObject = NaturalDocs::Project::ImageFile->New($lastModified, ::FILE_DOESNTEXIST(), $wasUsed);
        -                $imageFiles{$imageFile} = $imageFileObject;
        -
        -                if ($wasUsed)
        -                    {  $imageFilesToPurge{$imageFile} = 1;  };
        -                }
        -            else
        -                {
        -                $imageFileObject->SetWasUsed($wasUsed);
        -
        -                # This will be removed if it gets any references.
        -                if ($wasUsed)
        -                    {  $imageFilesToPurge{$imageFile} = 1;  };
        -
        -                if ($imageFileObject->LastModified() == $lastModified && !$rebuildEverything)
        -                    {  $imageFileObject->SetStatus(::FILE_SAME());  }
        -                else
        -                    {  $imageFileObject->SetStatus(::FILE_CHANGED());  };
        -                };
        -            };
        -
        -        NaturalDocs::BinaryFile->Close();
        -        }
        -
        -    else # !$fileIsOkay
        -        {
        -        $self->RebuildEverything();
        -        };
        -    };
        -
        -
        -#
        -#   Function: SaveImageFileInfo
        -#
        -#   Saves the image file info to disk.
        -#
        -sub SaveImageFileInfo
        -    {
        -    my $self = shift;
        -
        -    NaturalDocs::BinaryFile->OpenForWriting( NaturalDocs::Project->DataFile('ImageFileInfo.nd') );
        -
        -    while (my ($imageFile, $imageFileInfo) = each %imageFiles)
        -        {
        -        if ($imageFileInfo->Status() != ::FILE_DOESNTEXIST())
        -            {
        -            # [AString16: file name or undef]
        -            # [UInt32: last modification time]
        -            # [UInt8: was used]
        -
        -            NaturalDocs::BinaryFile->WriteAString16($imageFile);
        -            NaturalDocs::BinaryFile->WriteUInt32($imageFileInfo->LastModified());
        -            NaturalDocs::BinaryFile->WriteUInt8( ($imageFileInfo->ReferenceCount() > 0 ? 1 : 0) );
        -            };
        -        };
        -
        -    NaturalDocs::BinaryFile->WriteAString16(undef);
        -    NaturalDocs::BinaryFile->Close();
        -    };
        -
        -
        -#
        -#   Function: MigrateOldFiles
        -#
        -#   If the project uses the old file names used prior to 1.14, it converts them to the new file names.
        -#
        -sub MigrateOldFiles
        -    {
        -    my ($self) = @_;
        -
        -    my $projectDirectory = NaturalDocs::Settings->ProjectDirectory();
        -
        -    # We use the menu file as a test to see if we're using the new format.
        -    if (-e NaturalDocs::File->JoinPaths($projectDirectory, 'NaturalDocs_Menu.txt'))
        -        {
        -        # The Data subdirectory would have been created by NaturalDocs::Settings.
        -
        -        rename( NaturalDocs::File->JoinPaths($projectDirectory, 'NaturalDocs_Menu.txt'), $self->UserConfigFile('Menu.txt') );
        -
        -        if (-e NaturalDocs::File->JoinPaths($projectDirectory, 'NaturalDocs.sym'))
        -            {  rename( NaturalDocs::File->JoinPaths($projectDirectory, 'NaturalDocs.sym'), $self->DataFile('SymbolTable.nd') );  };
        -
        -        if (-e NaturalDocs::File->JoinPaths($projectDirectory, 'NaturalDocs.files'))
        -            {  rename( NaturalDocs::File->JoinPaths($projectDirectory, 'NaturalDocs.files'), $self->DataFile('FileInfo.nd') );  };
        -
        -        if (-e NaturalDocs::File->JoinPaths($projectDirectory, 'NaturalDocs.m'))
        -            {  rename( NaturalDocs::File->JoinPaths($projectDirectory, 'NaturalDocs.m'), $self->DataFile('PreviousMenuState.nd') );  };
        -        };
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Config and Data File Functions
        -
        -
        -#
        -#   Function: MainConfigFile
        -#
        -#   Returns the full path to the passed main configuration file.  Pass the file name only.
        -#
        -sub MainConfigFile #(string file)
        -    {
        -    my ($self, $file) = @_;
        -    return NaturalDocs::File->JoinPaths( NaturalDocs::Settings->ConfigDirectory(), $file );
        -    };
        -
        -#
        -#   Function: MainConfigFileStatus
        -#
        -#   Returns the <FileStatus> of the passed main configuration file.  Pass the file name only.
        -#
        -sub MainConfigFileStatus #(string file)
        -    {
        -    my ($self, $file) = @_;
        -    return $mainConfigFiles{$file};
        -    };
        -
        -#
        -#   Function: UserConfigFile
        -#
        -#   Returns the full path to the passed user configuration file.  Pass the file name only.
        -#
        -sub UserConfigFile #(string file)
        -    {
        -    my ($self, $file) = @_;
        -    return NaturalDocs::File->JoinPaths( NaturalDocs::Settings->ProjectDirectory(), $file );
        -    };
        -
        -#
        -#   Function: UserConfigFileStatus
        -#
        -#   Returns the <FileStatus> of the passed user configuration file.  Pass the file name only.
        -#
        -sub UserConfigFileStatus #(string file)
        -    {
        -    my ($self, $file) = @_;
        -    return $userConfigFiles{$file};
        -    };
        -
        -#
        -#   Function: DataFile
        -#
        -#   Returns the full path to the passed data file.  Pass the file name only.
        -#
        -sub DataFile #(string file)
        -    {
        -    my ($self, $file) = @_;
        -    return NaturalDocs::File->JoinPaths( NaturalDocs::Settings->ProjectDataDirectory(), $file );
        -    };
        -
        -
        -
        -
        -###############################################################################
        -# Group: Source File Functions
        -
        -
        -# Function: FilesToParse
        -# Returns an existence hashref of the <FileNames> to parse.  This is not a copy of the data, so don't change it.
        -sub FilesToParse
        -    {  return \%filesToParse;  };
        -
        -# Function: FilesToBuild
        -# Returns an existence hashref of the <FileNames> to build.  This is not a copy of the data, so don't change it.
        -sub FilesToBuild
        -    {  return \%filesToBuild;  };
        -
        -# Function: FilesToPurge
        -# Returns an existence hashref of the <FileNames> that had content last time, but now either don't anymore or were deleted.
        -# This is not a copy of the data, so don't change it.
        -sub FilesToPurge
        -    {  return \%filesToPurge;  };
        -
        -#
        -#   Function: RebuildFile
        -#
        -#   Adds the file to the list of files to build.  This function will automatically filter out files that don't have Natural Docs content and
        -#   files that are part of <FilesToPurge()>.  If this gets called on a file and that file later gets Natural Docs content, it will be added.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName> to build or rebuild.
        -#
        -sub RebuildFile #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    # We don't want to add it to the build list if it doesn't exist, doesn't have Natural Docs content, or it's going to be purged.
        -    # If it wasn't parsed yet and will later be found to have ND content, it will be added by SetHasContent().
        -    if (exists $supportedFiles{$file} && !exists $filesToPurge{$file} && $supportedFiles{$file}->HasContent())
        -        {
        -        $filesToBuild{$file} = 1;
        -
        -        if (exists $unbuiltFilesWithContent{$file})
        -            {  delete $unbuiltFilesWithContent{$file};  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: ReparseEverything
        -#
        -#   Adds all supported files to the list of files to parse.  This does not necessarily mean these files are going to be rebuilt.
        -#
        -sub ReparseEverything
        -    {
        -    my ($self) = @_;
        -
        -    if (!$reparseEverything)
        -        {
        -        foreach my $file (keys %supportedFiles)
        -            {
        -            $filesToParse{$file} = 1;
        -            };
        -
        -        $reparseEverything = 1;
        -        };
        -    };
        -
        -
        -#
        -#   Function: RebuildEverything
        -#
        -#   Adds all supported files to the list of files to build.  This does not necessarily mean these files are going to be reparsed.
        -#
        -sub RebuildEverything
        -    {
        -    my ($self) = @_;
        -
        -    foreach my $file (keys %unbuiltFilesWithContent)
        -        {
        -        $filesToBuild{$file} = 1;
        -        };
        -
        -    %unbuiltFilesWithContent = ( );
        -    $rebuildEverything = 1;
        -
        -    NaturalDocs::SymbolTable->RebuildAllIndexes();
        -
        -    if ($userConfigFiles{'Menu.txt'} == ::FILE_SAME())
        -        {  $userConfigFiles{'Menu.txt'} = ::FILE_CHANGED();  };
        -
        -    while (my ($imageFile, $imageObject) = each %imageFiles)
        -        {
        -        if ($imageObject->ReferenceCount())
        -            {  $imageFilesToUpdate{$imageFile} = 1;  };
        -        };
        -    };
        -
        -
        -# Function: UnbuiltFilesWithContent
        -# Returns an existence hashref of the <FileNames> that have Natural Docs content but are not part of <FilesToBuild()>.  This is
        -# not a copy of the data so don't change it.
        -sub UnbuiltFilesWithContent
        -    {  return \%unbuiltFilesWithContent;  };
        -
        -# Function: FilesWithContent
        -# Returns and existence hashref of the <FileNames> that have Natural Docs content.
        -sub FilesWithContent
        -    {
        -    # Don't keep this one internally, but there's an easy way to make it.
        -    return { %filesToBuild, %unbuiltFilesWithContent };
        -    };
        -
        -
        -#
        -#   Function: HasContent
        -#
        -#   Returns whether the <FileName> contains Natural Docs content.
        -#
        -sub HasContent #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    if (exists $supportedFiles{$file})
        -        {  return $supportedFiles{$file}->HasContent();  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: SetHasContent
        -#
        -#   Sets whether the <FileName> has Natural Docs content or not.
        -#
        -sub SetHasContent #(file, hasContent)
        -    {
        -    my ($self, $file, $hasContent) = @_;
        -
        -    if (exists $supportedFiles{$file} && $supportedFiles{$file}->HasContent() != $hasContent)
        -        {
        -        # If the file now has content...
        -        if ($hasContent)
        -            {
        -            $filesToBuild{$file} = 1;
        -            }
        -
        -        # If the file's content has been removed...
        -        else
        -            {
        -            delete $filesToBuild{$file};  # may not be there
        -            $filesToPurge{$file} = 1;
        -            };
        -
        -        $supportedFiles{$file}->SetHasContent($hasContent);
        -        };
        -    };
        -
        -
        -#
        -#   Function: StatusOf
        -#
        -#   Returns the <FileStatus> of the passed <FileName>.
        -#
        -sub StatusOf #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    if (exists $supportedFiles{$file})
        -        {  return $supportedFiles{$file}->Status();  }
        -    else
        -        {  return ::FILE_DOESNTEXIST();  };
        -    };
        -
        -
        -#
        -#   Function: DefaultMenuTitleOf
        -#
        -#   Returns the default menu title of the <FileName>.  If one isn't specified, it returns the <FileName>.
        -#
        -sub DefaultMenuTitleOf #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    if (exists $supportedFiles{$file})
        -        {  return $supportedFiles{$file}->DefaultMenuTitle();  }
        -    else
        -        {  return $file;  };
        -    };
        -
        -
        -#
        -#   Function: SetDefaultMenuTitle
        -#
        -#   Sets the <FileName's> default menu title.
        -#
        -sub SetDefaultMenuTitle #(file, menuTitle)
        -    {
        -    my ($self, $file, $menuTitle) = @_;
        -
        -    if (exists $supportedFiles{$file} && $supportedFiles{$file}->DefaultMenuTitle() ne $menuTitle)
        -        {
        -        $supportedFiles{$file}->SetDefaultMenuTitle($menuTitle);
        -        NaturalDocs::Menu->OnDefaultTitleChange($file);
        -        };
        -    };
        -
        -
        -#
        -#   Function: MostUsedLanguage
        -#
        -#   Returns the name of the most used language in the source trees.  Does not include text files.
        -#
        -sub MostUsedLanguage
        -    {  return $mostUsedLanguage;  };
        -
        -
        -
        -
        -###############################################################################
        -# Group: Image File Functions
        -
        -
        -#
        -#   Function: ImageFileExists
        -#   Returns whether the passed image file exists.
        -#
        -sub ImageFileExists #(FileName file) => bool
        -    {
        -    my ($self, $file) = @_;
        -
        -    if (!exists $imageFiles{$file})
        -        {  $file = $insensitiveImageFiles{lc($file)};  };
        -
        -    return (exists $imageFiles{$file} && $imageFiles{$file}->Status() != ::FILE_DOESNTEXIST());
        -    };
        -
        -
        -#
        -#   Function: ImageFileDimensions
        -#   Returns the dimensions of the passed image file as the array ( width, height ).  Returns them both as undef if it cannot be
        -#   determined.
        -#
        -sub ImageFileDimensions #(FileName file) => (int, int)
        -    {
        -    my ($self, $file) = @_;
        -
        -    if (!exists $imageFiles{$file})
        -        {  $file = $insensitiveImageFiles{lc($file)};  };
        -
        -    my $object = $imageFiles{$file};
        -    if (!$object)
        -        {  die "Tried to get the dimensions of an image that doesn't exist.";  };
        -
        -    if ($object->Width() == -1)
        -        {  $self->DetermineImageDimensions($file);  };
        -
        -    return ($object->Width(), $object->Height());
        -    };
        -
        -
        -#
        -#   Function: ImageFileCapitalization
        -#   Returns the properly capitalized version of the passed image <FileName>.  Image file paths are treated as case insensitive
        -#   regardless of whether the underlying operating system is or not, so we have to make sure the final version matches the
        -#   capitalization of the actual file.
        -#
        -sub ImageFileCapitalization #(FileName file) => FileName
        -    {
        -    my ($self, $file) = @_;
        -
        -    if (exists $imageFiles{$file})
        -        {  return $file;  }
        -    elsif (exists $insensitiveImageFiles{lc($file)})
        -        {  return $insensitiveImageFiles{lc($file)};  }
        -    else
        -        {  die "Tried to get the capitalization of an image file that doesn't exist.";  };
        -    };
        -
        -
        -#
        -#   Function: AddImageFileReference
        -#   Adds a reference to the passed image <FileName>.
        -#
        -sub AddImageFileReference #(FileName imageFile)
        -    {
        -    my ($self, $imageFile) = @_;
        -
        -    if (!exists $imageFiles{$imageFile})
        -        {  $imageFile = $insensitiveImageFiles{lc($imageFile)};  };
        -
        -    my $imageFileInfo = $imageFiles{$imageFile};
        -
        -    if ($imageFileInfo == undef || $imageFileInfo->Status() == ::FILE_DOESNTEXIST())
        -        {  die "Tried to add a reference to a non-existant image file.";  };
        -
        -    if ($imageFileInfo->AddReference() == 1)
        -        {
        -        delete $imageFilesToPurge{$imageFile};
        -
        -        if (!$imageFileInfo->WasUsed() ||
        -            $imageFileInfo->Status() == ::FILE_NEW() ||
        -            $imageFileInfo->Status() == ::FILE_CHANGED())
        -            {  $imageFilesToUpdate{$imageFile} = 1;  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: DeleteImageFileReference
        -#   Deletes a reference from the passed image <FileName>.
        -#
        -sub DeleteImageFileReference #(FileName imageFile)
        -    {
        -    my ($self, $imageFile) = @_;
        -
        -    if (!exists $imageFiles{$imageFile})
        -        {  $imageFile = $insensitiveImageFiles{lc($imageFile)};  };
        -
        -    if (!exists $imageFiles{$imageFile})
        -        {  die "Tried to delete a reference to a non-existant image file.";  };
        -
        -    if ($imageFiles{$imageFile}->DeleteReference() == 0)
        -        {
        -        delete $imageFilesToUpdate{$imageFile};
        -
        -        if ($imageFiles{$imageFile}->WasUsed())
        -            {  $imageFilesToPurge{$imageFile} = 1;  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: ImageFilesToUpdate
        -#   Returns an existence hashref of image <FileNames> that need to be updated.  *Do not change.*
        -#
        -sub ImageFilesToUpdate
        -    {  return \%imageFilesToUpdate;  };
        -
        -
        -#
        -#   Function: ImageFilesToPurge
        -#   Returns an existence hashref of image <FileNames> that need to be updated.  *Do not change.*
        -#
        -sub ImageFilesToPurge
        -    {  return \%imageFilesToPurge;  };
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -#
        -#   Function: GetAllSupportedFiles
        -#
        -#   Gets all the supported files in the passed directory and its subdirectories and puts them into <supportedFiles>.  The only
        -#   attribute that will be set is <NaturalDocs::Project::SourceFile->LastModified()>.  Also sets <mostUsedLanguage>.
        -#
        -sub GetAllSupportedFiles
        -    {
        -    my ($self) = @_;
        -
        -    my @directories = @{NaturalDocs::Settings->InputDirectories()};
        -    my $isCaseSensitive = NaturalDocs::File->IsCaseSensitive();
        -
        -    # Keys are language names, values are counts.
        -    my %languageCounts;
        -
        -
        -    # Make an existence hash of excluded directories.
        -
        -    my %excludedDirectories;
        -    my $excludedDirectoryArrayRef = NaturalDocs::Settings->ExcludedInputDirectories();
        -
        -    foreach my $excludedDirectory (@$excludedDirectoryArrayRef)
        -        {
        -        if ($isCaseSensitive)
        -            {  $excludedDirectories{$excludedDirectory} = 1;  }
        -        else
        -            {  $excludedDirectories{lc($excludedDirectory)} = 1;  };
        -        };
        -
        -
        -    my $imagesOnly;
        -    my $language;
        -
        -    while (scalar @directories)
        -        {
        -        my $directory = pop @directories;
        -
        -        opendir DIRECTORYHANDLE, $directory;
        -        my @entries = readdir DIRECTORYHANDLE;
        -        closedir DIRECTORYHANDLE;
        -
        -        @entries = NaturalDocs::File->NoUpwards(@entries);
        -
        -        foreach my $entry (@entries)
        -            {
        -            my $fullEntry = NaturalDocs::File->JoinPaths($directory, $entry);
        -
        -            # If an entry is a directory, recurse.
        -            if (-d $fullEntry)
        -                {
        -                # Join again with the noFile flag set in case the platform handles them differently.
        -                $fullEntry = NaturalDocs::File->JoinPaths($directory, $entry, 1);
        -
        -                if ($isCaseSensitive)
        -                    {
        -                    if (!exists $excludedDirectories{$fullEntry})
        -                        {  push @directories, $fullEntry;  };
        -                    }
        -                else
        -                    {
        -                    if (!exists $excludedDirectories{lc($fullEntry)})
        -                        {  push @directories, $fullEntry;  };
        -                    };
        -                }
        -
        -            # Otherwise add it if it's a supported extension.
        -            else
        -                {
        -                my $extension = NaturalDocs::File->ExtensionOf($entry);
        -
        -                if (exists $imageFileExtensions{lc($extension)})
        -                    {
        -                    my $fileObject = NaturalDocs::Project::ImageFile->New( (stat($fullEntry))[9], ::FILE_NEW(), 0 );
        -                    $imageFiles{$fullEntry} = $fileObject;
        -
        -                    my $lcFullEntry = lc($fullEntry);
        -
        -                    if (!exists $insensitiveImageFiles{$lcFullEntry} ||
        -                        ($fullEntry cmp $insensitiveImageFiles{$lcFullEntry}) < 0)
        -                        {
        -                        $insensitiveImageFiles{$lcFullEntry} = $fullEntry;
        -                        };
        -                    }
        -                elsif (!$imagesOnly && ($language = NaturalDocs::Languages->LanguageOf($fullEntry)) )
        -                    {
        -                    my $fileObject = NaturalDocs::Project::SourceFile->New();
        -                    $fileObject->SetLastModified(( stat($fullEntry))[9] );
        -                    $supportedFiles{$fullEntry} = $fileObject;
        -
        -                    $languageCounts{$language->Name()}++;
        -                    };
        -                };
        -            };
        -
        -
        -        # After we run out of source directories, add the image directories.
        -
        -        if (scalar @directories == 0 && !$imagesOnly)
        -            {
        -            $imagesOnly = 1;
        -            @directories = @{NaturalDocs::Settings->ImageDirectories()};
        -            };
        -        };
        -
        -
        -    my $topCount = 0;
        -
        -    while (my ($language, $count) = each %languageCounts)
        -        {
        -        if ($count > $topCount && $language ne 'Text File')
        -            {
        -            $topCount = $count;
        -            $mostUsedLanguage = $language;
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: DetermineImageDimensions
        -#
        -#   Attempts to determine the dimensions of the passed image and apply them to their object in <imageFiles>.  Will set them to
        -#   undef if they can't be determined.
        -#
        -sub DetermineImageDimensions #(FileName imageFile)
        -    {
        -    my ($self, $imageFile) = @_;
        -
        -    my $imageFileObject = $imageFiles{$imageFile};
        -    if (!defined $imageFileObject)
        -        {  die "Tried to determine image dimensions of a file with no object.";  };
        -
        -    my $extension = lc( NaturalDocs::File->ExtensionOf($imageFile) );
        -    my ($width, $height);
        -
        -    if ($imageFileExtensions{$extension})
        -        {
        -        open(FH_IMAGEFILE, '<' . $imageFile)
        -            or die 'Could not open ' . $imageFile . "\n";
        -        binmode(FH_IMAGEFILE);
        -
        -        my $raw;
        -
        -        if ($extension eq 'gif')
        -            {
        -            read(FH_IMAGEFILE, $raw, 6);
        -
        -            if ($raw eq 'GIF87a' || $raw eq 'GIF89a')
        -                {
        -                read(FH_IMAGEFILE, $raw, 4);
        -                ($width, $height) = unpack('vv', $raw);
        -                };
        -            }
        -
        -        elsif ($extension eq 'png')
        -            {
        -            read(FH_IMAGEFILE, $raw, 8);
        -
        -            if ($raw eq "\x89PNG\x0D\x0A\x1A\x0A")
        -                {
        -                seek(FH_IMAGEFILE, 4, 1);
        -                read(FH_IMAGEFILE, $raw, 4);
        -
        -                if ($raw eq 'IHDR')
        -                    {
        -                    read(FH_IMAGEFILE, $raw, 8);
        -                    ($width, $height) = unpack('NN', $raw);
        -                    };
        -                };
        -            }
        -
        -        elsif ($extension eq 'bmp')
        -            {
        -            read(FH_IMAGEFILE, $raw, 2);
        -
        -            if ($raw eq 'BM')
        -                {
        -                seek(FH_IMAGEFILE, 16, 1);
        -                read(FH_IMAGEFILE, $raw, 8);
        -
        -                ($width, $height) = unpack('VV', $raw);
        -                };
        -            }
        -
        -        elsif ($extension eq 'jpg' || $extension eq 'jpeg')
        -            {
        -            read(FH_IMAGEFILE, $raw, 2);
        -            my $isOkay = ($raw eq "\xFF\xD8");
        -
        -            while ($isOkay)
        -                {
        -                read(FH_IMAGEFILE, $raw, 4);
        -                my ($marker, $code, $length) = unpack('CCn', $raw);
        -
        -                $isOkay = ($marker eq 0xFF);
        -
        -                if ($isOkay)
        -                    {
        -                    if ($code >= 0xC0 && $code <= 0xC3)
        -                        {
        -                        read(FH_IMAGEFILE, $raw, 5);
        -                        ($height, $width) = unpack('xnn', $raw);
        -                        last;
        -                        }
        -
        -                    else
        -                        {
        -                        $isOkay = seek(FH_IMAGEFILE, $length - 2, 1);
        -                        };
        -                    };
        -                };
        -            };
        -
        -        close(FH_IMAGEFILE);
        -        };
        -
        -
        -    # Sanity check the values.  Although images can theoretically be bigger than 5000, most won't.  The worst that happens in this
        -    # case is just that they don't get length and width values in the output anyway.
        -    if ($width > 0 && $width < 5000 && $height > 0 && $height < 5000)
        -        {  $imageFileObject->SetDimensions($width, $height);  }
        -    else
        -        {  $imageFileObject->SetDimensions(undef, undef);  };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Project/ImageFile.pm b/vendor/naturaldocs/Modules/NaturalDocs/Project/ImageFile.pm
        deleted file mode 100644
        index f72adc44e..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Project/ImageFile.pm
        +++ /dev/null
        @@ -1,161 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Project::ImageFile
        -#
        -###############################################################################
        -#
        -#   A simple information class about project image files.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Project::ImageFile;
        -
        -
        -
        -###############################################################################
        -# Group: Implementation
        -
        -#
        -#   Constants: Members
        -#
        -#   The class is implemented as a blessed arrayref.  The following constants are used as indexes.
        -#
        -#       LAST_MODIFIED - The integer timestamp of when the file was last modified.
        -#       STATUS - <FileStatus> since the last build.
        -#       REFERENCE_COUNT - The number of references to the image from the source files.
        -#       WAS_USED - Whether the image was used the last time Natural Docs was run.
        -#       WIDTH - The image width.  Undef if can't be determined, -1 if haven't attempted to determine yet.
        -#       HEIGHT - The image height.  Undef if can't be determined, -1 if haven't attempted to determine yet.
        -#
        -
        -use NaturalDocs::DefineMembers 'LAST_MODIFIED', 'LastModified()', 'SetLastModified()',
        -                                                 'STATUS', 'Status()', 'SetStatus()',
        -                                                 'REFERENCE_COUNT', 'ReferenceCount()',
        -                                                 'WAS_USED', 'WasUsed()', 'SetWasUsed()',
        -                                                 'WIDTH', 'Width()',
        -                                                 'HEIGHT', 'Height()';
        -
        -
        -#
        -#   Topic: WasUsed versus References
        -#
        -#   <WasUsed()> is a simple true/false that notes whether this image file was used the last time Natural Docs was run.
        -#   <ReferenceCount()> is a counter for the number of times it's used *this* run.  As such, it starts at zero regardless of whether
        -#   <WasUsed()> is set or not.
        -#
        -
        -
        -###############################################################################
        -# Group: Functions
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new file object.
        -#
        -#   Parameters:
        -#
        -#       lastModified - The image file's last modification timestamp
        -#       status - The <FileStatus>.
        -#       wasUsed - Whether this image file was used the *last* time Natural Docs was run.
        -#
        -sub New #(timestamp lastModified, FileStatus status, bool wasUsed)
        -    {
        -    my ($package, $lastModified, $status, $width, $height, $wasUsed) = @_;
        -
        -    my $object = [ ];
        -    $object->[LAST_MODIFIED] = $lastModified;
        -    $object->[STATUS] = $status;
        -    $object->[REFERENCE_COUNT] = 0;
        -    $object->[WAS_USED] = $wasUsed;
        -    $object->[WIDTH] = -1;
        -    $object->[HEIGHT] = -1;
        -
        -    bless $object, $package;
        -
        -    return $object;
        -    };
        -
        -
        -#
        -#   Functions: Member Functions
        -#
        -#   LastModified - Returns the integer timestamp of when the file was last modified.
        -#   SetLastModified - Sets the file's last modification timestamp.
        -#   Status - Returns the <FileStatus> since the last build.
        -#   SetStatus - Sets the <FileStatus> since the last build.
        -#
        -
        -#
        -#   Function: ReferenceCount
        -#   Returns the current number of references to this image file during *this* Natural Docs execution.
        -#
        -
        -#
        -#   Function: AddReference
        -#   Increases the number of references to this image file by one.  Returns the new reference count.
        -#
        -sub AddReference
        -    {
        -    my $self = shift;
        -
        -    $self->[REFERENCE_COUNT]++;
        -    return $self->[REFERENCE_COUNT];
        -    };
        -
        -#
        -#   Function: DeleteReference
        -#   Decreases the number of references to this image file by one.  Returns the new reference count.
        -#
        -sub DeleteReference
        -    {
        -    my $self = shift;
        -    $self->[REFERENCE_COUNT]--;
        -
        -    if ($self->[REFERENCE_COUNT] < 0)
        -        {  die "Deleted more references to an image file than existed.";  };
        -
        -    return $self->[REFERENCE_COUNT];
        -    };
        -
        -
        -#
        -#   Functions: Member Functions
        -#
        -#   WasUsed - Returns whether this image file was used during the *last* Natural Docs execution.
        -#   SetWasUsed - Sets whether this image file was used during the *last* Natural Docs execution.
        -#   Width - Returns the width in pixels, undef if it can't be determined, and -1 if determination hasn't been attempted yet.
        -#   Height - Returns the width in pixels, undef if it can't be determined, and -1 if determination hasn't been attempted yet.
        -#
        -
        -
        -#
        -#   Function: SetDimensions
        -#   Sets the width and height of the image.  Set to undef if they can't be determined.
        -#
        -sub SetDimensions #(int width, int height)
        -    {
        -    my ($self, $width, $height) = @_;
        -
        -    # If either are undef, both should be undef.  This will also convert zeroes to undef.
        -    if (!$width || !$height)
        -        {
        -        $self->[WIDTH] = undef;
        -        $self->[HEIGHT] = undef;
        -        }
        -    else
        -        {
        -        $self->[WIDTH] = $width;
        -        $self->[HEIGHT] = $height;
        -        };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Project/SourceFile.pm b/vendor/naturaldocs/Modules/NaturalDocs/Project/SourceFile.pm
        deleted file mode 100644
        index aff05c7a5..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Project/SourceFile.pm
        +++ /dev/null
        @@ -1,114 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Project::SourceFile
        -#
        -###############################################################################
        -#
        -#   A simple information class about project files.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Project::SourceFile;
        -
        -
        -
        -###############################################################################
        -# Group: Implementation
        -
        -#
        -#   Constants: Members
        -#
        -#   The class is implemented as a blessed arrayref.  The following constants are used as indexes.
        -#
        -#       HAS_CONTENT             - Whether the file contains Natural Docs content or not.
        -#       LAST_MODIFIED           - The integer timestamp of when the file was last modified.
        -#       STATUS                       - <FileStatus> since the last build.
        -#       DEFAULT_MENU_TITLE  - The file's default title in the menu.
        -#
        -
        -# DEPENDENCY: New() depends on its parameter list being in the same order as these constants.  If the order changes, New()
        -# needs to be changed.
        -use NaturalDocs::DefineMembers 'HAS_CONTENT', 'LAST_MODIFIED', 'STATUS', 'DEFAULT_MENU_TITLE';
        -
        -
        -###############################################################################
        -# Group: Functions
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new file object.
        -#
        -#   Parameters:
        -#
        -#       hasContent         - Whether the file contains Natural Docs content or not.
        -#       lastModified         - The integer timestamp of when the file was last modified.
        -#       status                 - The <FileStatus> since the last build.
        -#       defaultMenuTitle  - The file's title in the menu.
        -#
        -#   Returns:
        -#
        -#       A reference to the new object.
        -#
        -sub New #(hasContent, lastModified, status, defaultMenuTitle)
        -    {
        -    # DEPENDENCY: This function depends on its parameter list being in the same order as the member constants.  If either order
        -    # changes, this function needs to be changed.
        -
        -    my $package = shift;
        -
        -    my $object = [ @_ ];
        -    bless $object, $package;
        -
        -    return $object;
        -    };
        -
        -# Function: HasContent
        -# Returns whether the file contains Natural Docs content or not.
        -sub HasContent
        -    {  return $_[0]->[HAS_CONTENT];  };
        -
        -# Function: SetHasContent
        -# Sets whether the file contains Natural Docs content or not.
        -sub SetHasContent #(hasContent)
        -    {  $_[0]->[HAS_CONTENT] = $_[1];  };
        -
        -# Function: LastModified
        -# Returns the integer timestamp of when the file was last modified.
        -sub LastModified
        -    {  return $_[0]->[LAST_MODIFIED];  };
        -
        -# Function: SetLastModified
        -# Sets the file's last modification timestamp.
        -sub SetLastModified #(lastModified)
        -    {  $_[0]->[LAST_MODIFIED] = $_[1];  };
        -
        -# Function: Status
        -# Returns the <FileStatus> since the last build.
        -sub Status
        -    {  return $_[0]->[STATUS];  };
        -
        -# Function: SetStatus
        -# Sets the <FileStatus> since the last build.
        -sub SetStatus #(status)
        -    {  $_[0]->[STATUS] = $_[1];  };
        -
        -# Function: DefaultMenuTitle
        -# Returns the file's default title on the menu.
        -sub DefaultMenuTitle
        -    {  return $_[0]->[DEFAULT_MENU_TITLE];  };
        -
        -# Function: SetDefaultMenuTitle
        -# Sets the file's default title on the menu.
        -sub SetDefaultMenuTitle #(menuTitle)
        -    {  $_[0]->[DEFAULT_MENU_TITLE] = $_[1];  };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/ReferenceString.pm b/vendor/naturaldocs/Modules/NaturalDocs/ReferenceString.pm
        deleted file mode 100644
        index 31fef757b..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/ReferenceString.pm
        +++ /dev/null
        @@ -1,335 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::ReferenceString
        -#
        -###############################################################################
        -#
        -#   A package to manage <ReferenceString> handling throughout the program.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::ReferenceString;
        -
        -use vars '@ISA', '@EXPORT';
        -@ISA = 'Exporter';
        -@EXPORT = ( 'BINARYREF_NOTYPE', 'BINARYREF_NORESOLVINGFLAGS',
        -
        -                     'REFERENCE_TEXT', 'REFERENCE_CH_CLASS', 'REFERENCE_CH_PARENT',
        -
        -                     'RESOLVE_RELATIVE', 'RESOLVE_ABSOLUTE', 'RESOLVE_NOPLURAL', 'RESOLVE_NOUSING' );
        -
        -
        -#
        -#   Constants: Binary Format Flags
        -#
        -#   These flags can be combined to specify the format when using <ToBinaryFile()> and <FromBinaryFile()>.  All are exported
        -#   by default.
        -#
        -#   BINARYREF_NOTYPE - Do not include the <ReferenceType>.
        -#   BINARYREF_NORESOLVEFLAGS - Do not include the <Resolving Flags>.
        -#
        -use constant BINARYREF_NOTYPE => 0x01;
        -use constant BINARYREF_NORESOLVINGFLAGS => 0x02;
        -
        -
        -#
        -#   Constants: ReferenceType
        -#
        -#   The type of a reference.
        -#
        -#       REFERENCE_TEXT - The reference appears in the text of the documentation.
        -#       REFERENCE_CH_CLASS - A class reference handled by <NaturalDocs::ClassHierarchy>.
        -#       REFERENCE_CH_PARENT - A parent class reference handled by <NaturalDocs::ClassHierarchy>.
        -#
        -#   Dependencies:
        -#
        -#       - <ToBinaryFile()> and <FromBinaryFile()> require that these values fit into a UInt8, i.e. are <= 255.
        -#
        -use constant REFERENCE_TEXT => 1;
        -use constant REFERENCE_CH_CLASS => 2;
        -use constant REFERENCE_CH_PARENT => 3;
        -
        -
        -#
        -#   Constants: Resolving Flags
        -#
        -#   Used to influence the method of resolving references in <NaturalDocs::SymbolTable>.
        -#
        -#       RESOLVE_RELATIVE - The reference text is truly relative, rather than Natural Docs' semi-relative.
        -#       RESOLVE_ABSOLUTE - The reference text is always absolute.  No local or relative references.
        -#       RESOLVE_NOPLURAL - The reference text may not be interpreted as a plural, and thus match singular forms as well.
        -#       RESOLVE_NOUSING - The reference text may not include "using" statements when being resolved.
        -#
        -#       If neither <RESOLVE_RELATIVE> or <RESOLVE_ABSOLUTE> is specified, Natural Docs' semi-relative kicks in instead,
        -#       which is where links are interpreted as local, then global, then relative.  <RESOLVE_RELATIVE> states that links are
        -#       local, then relative, then global.
        -#
        -#   Dependencies:
        -#
        -#       - <ToBinaryFile()> and <FromBinaryFile()> require that these values fit into a UInt8, i.e. are <= 255.
        -#
        -use constant RESOLVE_RELATIVE => 0x01;
        -use constant RESOLVE_ABSOLUTE => 0x02;
        -use constant RESOLVE_NOPLURAL => 0x04;
        -use constant RESOLVE_NOUSING => 0x08;
        -
        -
        -#
        -#
        -#   Function: MakeFrom
        -#
        -#   Encodes the passed information as a <ReferenceString>.  The format of the string should be treated as opaque.  However, the
        -#   characteristic you can rely on is that the same string will always be made from the same parameters, and thus it's suitable
        -#   for comparison and use as hash keys.
        -#
        -#   Parameters:
        -#
        -#       type - The <ReferenceType>.
        -#       symbol - The <SymbolString> of the reference.
        -#       language - The name of the language that defines the file this reference appears in.
        -#       scope - The scope <SymbolString> the reference appears in, or undef if none.
        -#       using - An arrayref of scope <SymbolStrings> that are also available for checking due to the equivalent a "using" statement,
        -#                  or undef if none.
        -#       resolvingFlags - The <Resolving Flags> to use with this reference.  They are ignored if the type is <REFERENCE_TEXT>.
        -#
        -#   Returns:
        -#
        -#       The encoded <ReferenceString>.
        -#
        -sub MakeFrom #(ReferenceType type, SymbolString symbol, string language, SymbolString scope, SymbolString[]* using, flags resolvingFlags)
        -    {
        -    my ($self, $type, $symbol, $language, $scope, $using, $resolvingFlags) = @_;
        -
        -    if ($type == ::REFERENCE_TEXT() || $resolvingFlags == 0)
        -       {  $resolvingFlags = undef;  };
        -
        -    # The format is [type] 0x1E [resolving flags] 0x1E [symbol] 0x1E [scope] ( 0x1E [using] )*
        -    # If there is no scope and/or using, the separator characters still remain.
        -
        -    # DEPENDENCY: SymbolString->FromText() removed all 0x1E characters.
        -    # DEPENDENCY: SymbolString->FromText() doesn't use 0x1E characters in its encoding.
        -
        -    my $string = $type . "\x1E" . $symbol . "\x1E" . $language . "\x1E" . $resolvingFlags . "\x1E";
        -
        -    if (defined $scope)
        -        {
        -        $string .= $scope;
        -        };
        -
        -    $string .= "\x1E";
        -
        -    if (defined $using)
        -        {
        -        $string .= join("\x1E", @$using);
        -        };
        -
        -    return $string;
        -    };
        -
        -
        -#
        -#   Function: ToBinaryFile
        -#
        -#   Writes a <ReferenceString> to the passed filehandle.  Can also encode an undef.
        -#
        -#   Parameters:
        -#
        -#       fileHandle - The filehandle to write to.
        -#       referenceString - The <ReferenceString> to write, or undef.
        -#       binaryFormatFlags - Any <Binary Format Flags> you want to use to influence encoding.
        -#
        -#   Format:
        -#
        -#       > [SymbolString: Symbol or undef for an undef reference]
        -#       > [AString16: language]
        -#       > [SymbolString: Scope or undef for none]
        -#       >
        -#       > [SymbolString: Using or undef for none]
        -#       > [SymbolString: Using or undef for no more]
        -#       > ...
        -#       >
        -#       > [UInt8: Type unless BINARYREF_NOTYPE is set]
        -#       > [UInt8: Resolving Flags unless BINARYREF_NORESOLVINGFLAGS is set]
        -#
        -#   Dependencies:
        -#
        -#       - <ReferenceTypes> must fit into a UInt8.  All values must be <= 255.
        -#       - All <Resolving Flags> must fit into a UInt8.  All values must be <= 255.
        -#
        -sub ToBinaryFile #(FileHandle fileHandle, ReferenceString referenceString, flags binaryFormatFlags)
        -    {
        -    my ($self, $fileHandle, $referenceString, $binaryFormatFlags) = @_;
        -
        -    my ($type, $symbol, $language, $scope, $using, $resolvingFlags) = $self->InformationOf($referenceString);
        -
        -    # [SymbolString: Symbol or undef for an undef reference]
        -
        -    NaturalDocs::SymbolString->ToBinaryFile($fileHandle, $symbol);
        -
        -    # [AString16: language]
        -
        -    print $fileHandle pack('nA*', length $language, $language);
        -
        -    # [SymbolString: scope or undef if none]
        -
        -    NaturalDocs::SymbolString->ToBinaryFile($fileHandle, $scope);
        -
        -    # [SymbolString: using or undef if none/no more] ...
        -
        -    if (defined $using)
        -        {
        -        foreach my $usingScope (@$using)
        -            {  NaturalDocs::SymbolString->ToBinaryFile($fileHandle, $usingScope);  };
        -        };
        -
        -    NaturalDocs::SymbolString->ToBinaryFile($fileHandle, undef);
        -
        -    # [UInt8: Type unless BINARYREF_NOTYPE is set]
        -
        -    if (!($binaryFormatFlags & BINARYREF_NOTYPE))
        -        {  print $fileHandle pack('C', $type);  };
        -
        -    # [UInt8: Resolving Flags unless BINARYREF_NORESOLVINGFLAGS is set]
        -
        -    if (!($binaryFormatFlags & BINARYREF_NORESOLVINGFLAGS))
        -        {  print $fileHandle pack('C', $type);  };
        -    };
        -
        -
        -#
        -#   Function: FromBinaryFile
        -#
        -#   Reads a <ReferenceString> or undef from the passed filehandle.
        -#
        -#   Parameters:
        -#
        -#       fileHandle - The filehandle to read from.
        -#       binaryFormatFlags - Any <Binary Format Flags> you want to use to influence decoding.
        -#       type - The <ReferenceType> to use if <BINARYREF_NOTYPE> is set.
        -#       resolvingFlags - The <Resolving Flags> to use if <BINARYREF_NORESOLVINGFLAGS> is set.
        -#
        -#   Returns:
        -#
        -#       The <ReferenceString> or undef.
        -#
        -#   See Also:
        -#
        -#       See <ToBinaryFile()> for format and dependencies.
        -#
        -sub FromBinaryFile #(FileHandle fileHandle, flags binaryFormatFlags, ReferenceType type, flags resolvingFlags)
        -    {
        -    my ($self, $fileHandle, $binaryFormatFlags, $type, $resolvingFlags) = @_;
        -    my $raw;
        -
        -    # [SymbolString: Symbol or undef for an undef reference]
        -
        -    my $symbol = NaturalDocs::SymbolString->FromBinaryFile($fileHandle);
        -
        -    if (!defined $symbol)
        -        {  return undef;  };
        -
        -
        -    # [AString16: language]
        -
        -    read($fileHandle, $raw, 2);
        -    my $languageLength = unpack('n', $raw);
        -
        -    my $language;
        -    read($fileHandle, $language, $languageLength);
        -
        -
        -    # [SymbolString: scope or undef if none]
        -
        -    my $scope = NaturalDocs::SymbolString->FromBinaryFile($fileHandle);
        -
        -    # [SymbolString: using or undef if none/no more] ...
        -
        -    my $usingSymbol;
        -    my @using;
        -
        -    while ($usingSymbol = NaturalDocs::SymbolString->FromBinaryFile($fileHandle))
        -        {  push @using, $usingSymbol;  };
        -
        -    if (scalar @using)
        -        {  $usingSymbol = \@using;  }
        -    else
        -        {  $usingSymbol = undef;  };
        -
        -    # [UInt8: Type unless BINARYREF_NOTYPE is set]
        -
        -    if (!($binaryFormatFlags & BINARYREF_NOTYPE))
        -        {
        -        my $raw;
        -        read($fileHandle, $raw, 1);
        -        $type = unpack('C', $raw);
        -        };
        -
        -    # [UInt8: Resolving Flags unless BINARYREF_NORESOLVINGFLAGS is set]
        -
        -    if (!($binaryFormatFlags & BINARYREF_NORESOLVINGFLAGS))
        -        {
        -        my $raw;
        -        read($fileHandle, $raw, 1);
        -        $resolvingFlags = unpack('C', $raw);
        -        };
        -
        -    return $self->MakeFrom($type, $symbol, $language, $scope, $usingSymbol, $resolvingFlags);
        -    };
        -
        -
        -#
        -#   Function: InformationOf
        -#
        -#   Returns the information encoded in a <ReferenceString>.
        -#
        -#   Parameters:
        -#
        -#       referenceString - The <ReferenceString> to decode.
        -#
        -#   Returns:
        -#
        -#       The array ( type, symbol, language, scope, using, resolvingFlags ).
        -#
        -#       type - The <ReferenceType>.
        -#       symbol - The <SymbolString>.
        -#       language - The name of the language that defined the file the reference was defined in.
        -#       scope - The scope <SymbolString>, or undef if none.
        -#       using - An arrayref of scope <SymbolStrings> that the reference also has access to via "using" statements, or undef if none.
        -#       resolvingFlags - The <Resolving Flags> of the reference.
        -#
        -sub InformationOf #(ReferenceString referenceString)
        -    {
        -    my ($self, $referenceString) = @_;
        -
        -    my ($type, $symbolString, $language, $resolvingFlags, $scopeString, @usingStrings) = split(/\x1E/, $referenceString);
        -
        -    if (!length $resolvingFlags)
        -        {  $resolvingFlags = undef;  };
        -
        -    return ( $type, $symbolString, $language, $scopeString, [ @usingStrings ], $resolvingFlags );
        -    };
        -
        -
        -#
        -#   Function: TypeOf
        -#
        -#   Returns the <ReferenceType> encoded in the reference string.  This is faster than <InformationOf()> if this is
        -#   the only information you need.
        -#
        -sub TypeOf #(ReferenceString referenceString)
        -    {
        -    my ($self, $referenceString) = @_;
        -
        -    $referenceString =~ /^([^\x1E]+)/;
        -    return $1;
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Settings.pm b/vendor/naturaldocs/Modules/NaturalDocs/Settings.pm
        deleted file mode 100644
        index a9ed60c66..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Settings.pm
        +++ /dev/null
        @@ -1,1480 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Settings
        -#
        -###############################################################################
        -#
        -#   A package to handle the command line and various other program settings.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use Cwd ();
        -
        -use NaturalDocs::Settings::BuildTarget;
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Settings;
        -
        -
        -###############################################################################
        -# Group: Information
        -
        -=pod begin nd
        -
        -    Topic: Usage and Dependencies
        -
        -        - The <Constant Functions> can be called immediately.
        -
        -        - Prior to initialization, <NaturalDocs::Builder> must have all its output packages registered.
        -
        -        - To initialize, call <Load()>.  All functions except <InputDirectoryNameOf()> will then be available.
        -
        -        - <GenerateDirectoryNames()> must be called before <InputDirectoryNameOf()> will work.  Currently it is called by
        -          <NaturalDocs::Menu->LoadAndUpdate()>.
        -
        -
        -    Architecture: Internal Overview
        -
        -        - <Load()> first parses the command line, gathering all the settings and checking for errors.  All <NaturalDocs::Builder>
        -          packages must be registered before this is called because it needs their command line options.
        -          <NaturalDocs::Project->ReparseEverything()> and <NaturalDocs::Project->RebuildEverything()> are called right away if -r
        -          or -ro are used.
        -
        -        - Output directories are *not* named at this point.  See <Named Directories>.
        -
        -        - The previous settings from the last time Natural Docs was run are loaded and compared to the current settings.
        -          <NaturalDocs::Project->ReparseEverything()> and <NaturalDocs::Project->RebuildEverything()> are called if there are
        -          any differences that warrant it.
        -
        -        - It then waits for <GenerateDirectoryNames()> to be called by <NaturalDocs::Menu>.  The reason for this is that the
        -          previous directory names are stored as hints in the menu file, for reasons explained in <Named Directories>.  Once that
        -          happens all the unnamed directories have names generated for them so everything is named.  The package is completely
        -          set up.
        -
        -        - The input directories are stored in an array instead of a hash because the order they were declared in matters.  If two
        -          people use multiple input directories on separate computers without sharing a menu file, they should at least get consistent
        -          directory names by declaring them in the same order.
        -
        -
        -    Architecture: Named Directories
        -
        -        Ever since Natural Docs introduced multiple input directories in 1.16, they've had to be named.  Since they don't necessarily
        -        extend from the same root anymore, they can't share an output directory without the risk of file name conflicts.  There was
        -        an early attempt at giving them actual names, but now they're just numbered from 1.
        -
        -        Directory names aren't generated right away.  It waits for <Menu.txt> to load because that holds the obfuscated names from
        -        the last run.  <NaturalDocs::Menu> then calls <GenerateDirectoryNames()> and passes those along as hints.
        -        <GenerateDirectoryNames()> then applies them to any matches and generates new ones for any remaining.  This is done so
        -        that output page locations can remain consistent when built on multiple computers, so long as the menu file is shared.  I tend
        -        to think the menu file is the most likely configuration file to be shared.
        -
        -
        -    Architecture: Removed Directories
        -
        -        Directories that were part of the previous run but aren't anymore are still stored in the package.  The primary reason, though
        -        there may be others, is file purging.  If an input directory is removed, all the output files that were generated from anything
        -        in it need to be removed.  To find out what the output file name was for a removed source file, it needs to be able to split it
        -        from it's original input directory and know what that directory was named.  If this didn't happen those output files would be
        -        orphaned, as was the case prior to 1.32.
        -
        -=cut
        -
        -
        -
        -###############################################################################
        -# Group: Variables
        -
        -
        -# handle: PREVIOUS_SETTINGS_FILEHANDLE
        -# The file handle used with <PreviousSettings.nd>.
        -
        -# array: inputDirectories
        -# An array of input directories.
        -my @inputDirectories;
        -
        -# array: inputDirectoryNames
        -# An array of the input directory names.  Each name corresponds to the directory of the same index in <inputDirectories>.
        -my @inputDirectoryNames;
        -
        -# array: imageDirectories
        -# An array of image directories.
        -my @imageDirectories;
        -
        -# array: imageDirectoryNames
        -# An array of the image directory names.  Each name corresponds to the directory of the same index in <imageDirectories>.
        -my @imageDirectoryNames;
        -
        -# array: relativeImageDirectories
        -# An array of the relative paths for images.  The asterisks found in the command line are not present.
        -my @relativeImageDirectories;
        -
        -# array: excludedInputDirectories
        -# An array of input directories to exclude.
        -my @excludedInputDirectories;
        -
        -# array: removedInputDirectories
        -# An array of input directories that were once in the command line but are no longer.
        -my @removedInputDirectories;
        -
        -# array: removedInputDirectoryNames
        -# An array of the removed input directories' names.  Each name corresponds to the directory of the same index in
        -# <removedInputDirectories>.
        -my @removedInputDirectoryNames;
        -
        -# array: removedImageDirectories
        -# An array of image directories that were once in the command line but are no longer.
        -my @removedImageDirectories;
        -
        -# array: removedImageDirectoryNames
        -# An array of the removed image directories' names.  Each name corresponds to the directory of the same index in
        -# <removedImageDirectories>.
        -my @removedImageDirectoryNames;
        -
        -# var: projectDirectory
        -# The project directory.
        -my $projectDirectory;
        -
        -# array: buildTargets
        -# An array of <NaturalDocs::Settings::BuildTarget>s.
        -my @buildTargets;
        -
        -# var: documentedOnly
        -# Whether undocumented code aspects should be included in the output.
        -my $documentedOnly;
        -
        -# int: tabLength
        -# The number of spaces in tabs.
        -my $tabLength;
        -
        -# bool: noAutoGroup
        -# Whether auto-grouping is turned off.
        -my $noAutoGroup;
        -
        -# bool: onlyFileTitles
        -# Whether source files should always use the file name as the title.
        -my $onlyFileTitles;
        -
        -# bool: isQuiet
        -# Whether the script should be run in quiet mode or not.
        -my $isQuiet;
        -
        -# bool: rebuildData
        -# WHether most data files should be ignored and rebuilt.
        -my $rebuildData;
        -
        -# array: styles
        -# An array of style names to use, most important first.
        -my @styles;
        -
        -# var: highlightCode
        -# Whether syntax highlighting should be applied to code tags.
        -my $highlightCode;
        -
        -# var: highlightAnonymous
        -# Whether syntax highlighting should be applied to anonymous code tags.
        -my $highlightAnonymous;
        -
        -
        -###############################################################################
        -# Group: Files
        -
        -
        -#
        -#   File: PreviousSettings.nd
        -#
        -#   Stores the previous command line settings.
        -#
        -#   Format:
        -#
        -#       > [BINARY_FORMAT]
        -#       > [VersionInt: app version]
        -#
        -#       The file starts with the standard <BINARY_FORMAT> <VersionInt> header.
        -#
        -#       > [UInt8: tab length]
        -#       > [UInt8: documented only (0 or 1)]
        -#       > [UInt8: no auto-group (0 or 1)]
        -#       > [UInt8: only file titles (0 or 1)]
        -#		> [UInt8: highlight code (0 or 1)]
        -#		> [UInt8: highlight anonymous (0 or 1)]
        -#       >
        -#       > [UInt8: number of input directories]
        -#       > [AString16: input directory] [AString16: input directory name] ...
        -#
        -#       A count of input directories, then that number of directory/name pairs.
        -#
        -#       > [UInt8: number of output targets]
        -#       > [AString16: output directory] [AString16: output format command line option] ...
        -#
        -#       A count of output targets, then that number of directory/format pairs.
        -#
        -#
        -#   Revisions:
        -#
        -#		1.51:
        -#
        -#			- Removed charset.
        -#
        -#		1.5:
        -#
        -#			- Added highlight code and highlight anonymous.
        -#
        -#       1.4:
        -#
        -#           - Added only file titles.
        -#
        -#       1.33:
        -#
        -#           - Added charset.
        -#
        -#       1.3:
        -#
        -#           - Removed headers-only, which was a 0/1 UInt8 after tab length.
        -#           - Change auto-group level (1 = no, 2 = yes, 3 = full only) to no auto-group (0 or 1).
        -#
        -#       1.22:
        -#
        -#           - Added auto-group level.
        -#
        -#       1.2:
        -#
        -#           - File was added to the project.  Prior to 1.2, it didn't exist.
        -#
        -
        -
        -###############################################################################
        -# Group: Action Functions
        -
        -#
        -#   Function: Load
        -#
        -#   Loads and parses all settings from the command line and configuration files.  Will exit if the options are invalid or the syntax
        -#   reference was requested.
        -#
        -sub Load
        -    {
        -    my ($self) = @_;
        -
        -    $self->ParseCommandLine();
        -    $self->LoadAndComparePreviousSettings();
        -    };
        -
        -
        -#
        -#   Function: Save
        -#
        -#   Saves all settings in configuration files to disk.
        -#
        -sub Save
        -    {
        -    my ($self) = @_;
        -
        -    $self->SavePreviousSettings();
        -    };
        -
        -
        -#
        -#   Function: GenerateDirectoryNames
        -#
        -#   Generates names for each of the input and image directories, which can later be retrieved with <InputDirectoryNameOf()>
        -#   and <ImageDirectoryNameOf()>.
        -#
        -#   Parameters:
        -#
        -#       inputHints - A hashref of suggested input directory names, where the keys are the directories and the values are the names.
        -#                        These take precedence over anything generated.  You should include names for directories that are no longer in
        -#                        the command line.  This parameter may be undef.
        -#       imageHints - Same as inputHints, only for the image directories.
        -#
        -sub GenerateDirectoryNames #(hashref inputHints, hashref imageHints)
        -    {
        -    my ($self, $inputHints, $imageHints) = @_;
        -
        -    my %usedInputNames;
        -    my %usedImageNames;
        -
        -
        -    if (defined $inputHints)
        -        {
        -        # First, we have to convert all non-numeric names to numbers, since they may come from a pre-1.32 menu file.  We do it
        -        # here instead of in NaturalDocs::Menu to keep the naming scheme centralized.
        -
        -        my @names = values %$inputHints;
        -        my $hasNonNumeric;
        -
        -        foreach my $name (@names)
        -            {
        -            if ($name !~ /^[0-9]+$/)
        -                {
        -                $hasNonNumeric = 1;
        -                last;
        -                };
        -            };
        -
        -
        -        if ($hasNonNumeric)
        -            {
        -            # Hash mapping old names to new names.
        -            my %conversion;
        -
        -            # The sequential number to use.  Starts at two because we want 'default' to be one.
        -            my $currentNumber = 2;
        -
        -            # If there's only one name, we set it to one no matter what it was set to before.
        -            if (scalar @names == 1)
        -                {  $conversion{$names[0]} = 1;  }
        -            else
        -                {
        -                # We sort the list first because we want the end result to be predictable.  This conversion could be happening on many
        -                # machines, and they may not all specify the input directories in the same order.  They need to all come up with the
        -                # same result.
        -                @names = sort @names;
        -
        -                foreach my $name (@names)
        -                    {
        -                    if ($name eq 'default')
        -                        {  $conversion{$name} = 1;  }
        -                    else
        -                        {
        -                        $conversion{$name} = $currentNumber;
        -                        $currentNumber++;
        -                        };
        -                    };
        -                };
        -
        -            # Convert them to the new names.
        -            foreach my $directory (keys %$inputHints)
        -                {
        -                $inputHints->{$directory} = $conversion{ $inputHints->{$directory} };
        -                };
        -            };
        -
        -
        -        # Now we apply all the names from the hints, and save any unused ones as removed directories.
        -
        -        for (my $i = 0; $i < scalar @inputDirectories; $i++)
        -            {
        -            if (exists $inputHints->{$inputDirectories[$i]})
        -                {
        -                $inputDirectoryNames[$i] = $inputHints->{$inputDirectories[$i]};
        -                $usedInputNames{ $inputDirectoryNames[$i] } = 1;
        -                delete $inputHints->{$inputDirectories[$i]};
        -                };
        -            };
        -
        -
        -        # Any remaining hints are saved as removed directories.
        -
        -        while (my ($directory, $name) = each %$inputHints)
        -            {
        -            push @removedInputDirectories, $directory;
        -            push @removedInputDirectoryNames, $name;
        -            };
        -        };
        -
        -
        -    if (defined $imageHints)
        -        {
        -        # Image directory names were never non-numeric, so there is no conversion.  Apply all the names from the hints.
        -
        -        for (my $i = 0; $i < scalar @imageDirectories; $i++)
        -            {
        -            if (exists $imageHints->{$imageDirectories[$i]})
        -                {
        -                $imageDirectoryNames[$i] = $imageHints->{$imageDirectories[$i]};
        -                $usedImageNames{ $imageDirectoryNames[$i] } = 1;
        -                delete $imageHints->{$imageDirectories[$i]};
        -                };
        -            };
        -
        -
        -        # Any remaining hints are saved as removed directories.
        -
        -        while (my ($directory, $name) = each %$imageHints)
        -            {
        -            push @removedImageDirectories, $directory;
        -            push @removedImageDirectoryNames, $name;
        -            };
        -        };
        -
        -
        -    # Now we generate names for anything remaining.
        -
        -    my $inputCounter = 1;
        -
        -    for (my $i = 0; $i < scalar @inputDirectories; $i++)
        -        {
        -        if (!defined $inputDirectoryNames[$i])
        -            {
        -            while (exists $usedInputNames{$inputCounter})
        -                {  $inputCounter++;  };
        -
        -            $inputDirectoryNames[$i] = $inputCounter;
        -            $usedInputNames{$inputCounter} = 1;
        -
        -            $inputCounter++;
        -            };
        -        };
        -
        -
        -    my $imageCounter = 1;
        -
        -    for (my $i = 0; $i < scalar @imageDirectories; $i++)
        -        {
        -        if (!defined $imageDirectoryNames[$i])
        -            {
        -            while (exists $usedImageNames{$imageCounter})
        -                {  $imageCounter++;  };
        -
        -            $imageDirectoryNames[$i] = $imageCounter;
        -            $usedImageNames{$imageCounter} = 1;
        -
        -            $imageCounter++;
        -            };
        -        };
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Information Functions
        -
        -
        -#
        -#   Function: InputDirectories
        -#
        -#   Returns an arrayref of input directories.  Do not change.
        -#
        -#   This will not return any removed input directories.
        -#
        -sub InputDirectories
        -    {  return \@inputDirectories;  };
        -
        -#
        -#   Function: InputDirectoryNameOf
        -#
        -#   Returns the generated name of the passed input directory.  <GenerateDirectoryNames()> must be called once before this
        -#   function is available.
        -#
        -#   If a name for a removed input directory is available, it will be returned as well.
        -#
        -sub InputDirectoryNameOf #(directory)
        -    {
        -    my ($self, $directory) = @_;
        -
        -    for (my $i = 0; $i < scalar @inputDirectories; $i++)
        -        {
        -        if ($directory eq $inputDirectories[$i])
        -            {  return $inputDirectoryNames[$i];  };
        -        };
        -
        -    for (my $i = 0; $i < scalar @removedInputDirectories; $i++)
        -        {
        -        if ($directory eq $removedInputDirectories[$i])
        -            {  return $removedInputDirectoryNames[$i];  };
        -        };
        -
        -    return undef;
        -    };
        -
        -
        -#
        -#   Function: SplitFromInputDirectory
        -#
        -#   Takes an input file name and returns the array ( inputDirectory, relativePath ).
        -#
        -#   If the file cannot be split from an input directory, it will try to do it with the removed input directories.
        -#
        -sub SplitFromInputDirectory #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    foreach my $directory (@inputDirectories, @removedInputDirectories)
        -        {
        -        if (NaturalDocs::File->IsSubPathOf($directory, $file))
        -            {  return ( $directory, NaturalDocs::File->MakeRelativePath($directory, $file) );  };
        -        };
        -
        -    return ( );
        -    };
        -
        -
        -#
        -#   Function: ImageDirectories
        -#
        -#   Returns an arrayref of image directories.  Do not change.
        -#
        -#   This will not return any removed image directories.
        -#
        -sub ImageDirectories
        -    {  return \@imageDirectories;  };
        -
        -
        -#
        -#   Function: ImageDirectoryNameOf
        -#
        -#   Returns the generated name of the passed image or input directory.  <GenerateDirectoryNames()> must be called once before
        -#   this function is available.
        -#
        -#   If a name for a removed input or image directory is available, it will be returned as well.
        -#
        -sub ImageDirectoryNameOf #(directory)
        -    {
        -    my ($self, $directory) = @_;
        -
        -    for (my $i = 0; $i < scalar @imageDirectories; $i++)
        -        {
        -        if ($directory eq $imageDirectories[$i])
        -            {  return $imageDirectoryNames[$i];  };
        -        };
        -
        -    for (my $i = 0; $i < scalar @removedImageDirectories; $i++)
        -        {
        -        if ($directory eq $removedImageDirectories[$i])
        -            {  return $removedImageDirectoryNames[$i];  };
        -        };
        -
        -    return undef;
        -    };
        -
        -
        -#
        -#   Function: SplitFromImageDirectory
        -#
        -#   Takes an input image file name and returns the array ( imageDirectory, relativePath ).
        -#
        -#   If the file cannot be split from an image directory, it will try to do it with the removed image directories.
        -#
        -sub SplitFromImageDirectory #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    foreach my $directory (@imageDirectories, @removedImageDirectories)
        -        {
        -        if (NaturalDocs::File->IsSubPathOf($directory, $file))
        -            {  return ( $directory, NaturalDocs::File->MakeRelativePath($directory, $file) );  };
        -        };
        -
        -    return ( );
        -    };
        -
        -
        -#
        -#   Function: RelativeImageDirectories
        -#
        -#   Returns an arrayref of relative image directories.  Do not change.
        -#
        -sub RelativeImageDirectories
        -    {  return \@relativeImageDirectories;  };
        -
        -
        -# Function: ExcludedInputDirectories
        -# Returns an arrayref of input directories to exclude.  Do not change.
        -sub ExcludedInputDirectories
        -    {  return \@excludedInputDirectories;  };
        -
        -
        -# Function: BuildTargets
        -# Returns an arrayref of <NaturalDocs::Settings::BuildTarget>s.  Do not change.
        -sub BuildTargets
        -    {  return \@buildTargets;  };
        -
        -
        -#
        -#   Function: OutputDirectoryOf
        -#
        -#   Returns the output directory of a builder object.
        -#
        -#   Parameters:
        -#
        -#       object - The builder object, whose class is derived from <NaturalDocs::Builder::Base>.
        -#
        -#   Returns:
        -#
        -#       The builder directory, or undef if the object wasn't found..
        -#
        -sub OutputDirectoryOf #(object)
        -    {
        -    my ($self, $object) = @_;
        -
        -    foreach my $buildTarget (@buildTargets)
        -        {
        -        if ($buildTarget->Builder() == $object)
        -            {  return $buildTarget->Directory();  };
        -        };
        -
        -    return undef;
        -    };
        -
        -
        -# Function: Styles
        -# Returns an arrayref of the styles associated with the output.
        -sub Styles
        -    {  return \@styles;  };
        -
        -# Function: ProjectDirectory
        -# Returns the project directory.
        -sub ProjectDirectory
        -    {  return $projectDirectory;  };
        -
        -# Function: ProjectDataDirectory
        -# Returns the project data directory.
        -sub ProjectDataDirectory
        -    {  return NaturalDocs::File->JoinPaths($projectDirectory, 'Data', 1);  };
        -
        -# Function: StyleDirectory
        -# Returns the main style directory.
        -sub StyleDirectory
        -    {  return NaturalDocs::File->JoinPaths($FindBin::RealBin, 'Styles', 1);  };
        -
        -# Function: JavaScriptDirectory
        -# Returns the main JavaScript directory.
        -sub JavaScriptDirectory
        -    {  return NaturalDocs::File->JoinPaths($FindBin::RealBin, 'JavaScript', 1);  };
        -
        -# Function: ConfigDirectory
        -# Returns the main configuration directory.
        -sub ConfigDirectory
        -    {  return NaturalDocs::File->JoinPaths($FindBin::RealBin, 'Config', 1);  };
        -
        -# Function: DocumentedOnly
        -# Returns whether undocumented code aspects should be included in the output.
        -sub DocumentedOnly
        -    {  return $documentedOnly;  };
        -
        -# Function: TabLength
        -# Returns the number of spaces tabs should be expanded to.
        -sub TabLength
        -    {  return $tabLength;  };
        -
        -# Function: NoAutoGroup
        -# Returns whether auto-grouping is turned off.
        -sub NoAutoGroup
        -    {  return $noAutoGroup;  };
        -
        -# Function: OnlyFileTitles
        -# Returns whether source files should always use the file name as the title.
        -sub OnlyFileTitles
        -    {  return $onlyFileTitles;  };
        -
        -# Function: IsQuiet
        -# Returns whether the script should be run in quiet mode or not.
        -sub IsQuiet
        -    {  return $isQuiet;  };
        -
        -# Function: RebuildData
        -# Returns whether all data files should be ignored and rebuilt.
        -sub RebuildData
        -    {  return $rebuildData;  };
        -
        -# Function: HighlightCode
        -# Returns whether to apply syntax highlighting (start code) sections.
        -sub HighlightCode
        -	{  return $highlightCode;  }
        -
        -# Function: HighlightAnonymous
        -# Returns whether to apply syntax highlighting to anonymous code sections designated with :, >, or |.
        -sub HighlightAnonymous
        -	{  return $highlightAnonymous;  }
        -
        -
        -###############################################################################
        -# Group: Constant Functions
        -
        -#
        -#   Function: AppVersion
        -#
        -#   Returns Natural Docs' version number as an integer.  Use <TextAppVersion()> to get a printable version.
        -#
        -sub AppVersion
        -    {
        -    my ($self) = @_;
        -    return NaturalDocs::Version->FromString($self->TextAppVersion());
        -    };
        -
        -#
        -#   Function: TextAppVersion
        -#
        -#   Returns Natural Docs' version number as plain text.
        -#
        -sub TextAppVersion
        -    {
        -    return '1.51';
        -    };
        -
        -#
        -#   Function: AppURL
        -#
        -#   Returns a string of the project's current web address.
        -#
        -sub AppURL
        -    {  return 'http://www.naturaldocs.org';  };
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -
        -#
        -#   Function: ParseCommandLine
        -#
        -#   Parses and validates the command line.  Will cause the script to exit if the options ask for the syntax reference or
        -#   are invalid.
        -#
        -sub ParseCommandLine
        -    {
        -    my ($self) = @_;
        -
        -    my %synonyms = ( 'input'    => '-i',
        -                                  'source' => '-i',
        -                                  'excludeinput' => '-xi',
        -                                  'excludesource' => '-xi',
        -                                  'images' => '-img',
        -                                  'output'  => '-o',
        -                                  'project' => '-p',
        -                                  'documentedonly' => '-do',
        -                                  'style'    => '-s',
        -                                  'rebuild' => '-r',
        -                                  'rebuildoutput' => '-ro',
        -                                  'tablength' => '-t',
        -                                  'quiet'    => '-q',
        -                                  'headersonly' => '-ho',
        -                                  'help'     => '-h',
        -                                  'autogroup' => '-ag',
        -                                  'noautogroup' => '-nag',
        -                                  'onlyfiletitles' => '-oft',
        -                                  'onlyfiletitle' => '-oft',
        -                                  'highlight' => '-hl',
        -                                  'highlighting' => '-hl' );
        -
        -
        -    my @errorMessages;
        -
        -    my $valueRef;
        -    my $option;
        -
        -    my @outputStrings;
        -    my @imageStrings;
        -    my $highlightString;
        -
        -
        -    # Sometimes $valueRef is set to $ignored instead of undef because we don't want certain errors to cause other,
        -    # unnecessary errors.  For example, if they set the input directory twice, we want to show that error and swallow the
        -    # specified directory without complaint.  Otherwise it would complain about the directory too as if it were random crap
        -    # inserted into the command line.
        -    my $ignored;
        -
        -    my $index = 0;
        -
        -    while ($index < scalar @ARGV)
        -        {
        -        my $arg = $ARGV[$index];
        -
        -        if (substr($arg, 0, 1) eq '-')
        -            {
        -            $option = lc($arg);
        -
        -            # Support options like -t2 as well as -t 2.
        -            if ($option =~ /^([^0-9]+)([0-9]+)$/)
        -                {
        -                $option = $1;
        -                splice(@ARGV, $index + 1, 0, $2);
        -                };
        -
        -            # Convert long forms to short.
        -            if (substr($option, 1, 1) eq '-')
        -                {
        -                # Strip all dashes.
        -                my $newOption = $option;
        -                $newOption =~ tr/-//d;
        -
        -                if (exists $synonyms{$newOption})
        -                    {  $option = $synonyms{$newOption};  }
        -                }
        -
        -            if ($option eq '-i')
        -                {
        -                push @inputDirectories, undef;
        -                $valueRef = \$inputDirectories[-1];
        -                }
        -            elsif ($option eq '-xi')
        -                {
        -                push @excludedInputDirectories, undef;
        -                $valueRef = \$excludedInputDirectories[-1];
        -                }
        -            elsif ($option eq '-img')
        -                {
        -                push @imageStrings, undef;
        -                $valueRef = \$imageStrings[-1];
        -                }
        -            elsif ($option eq '-p')
        -                {
        -                if (defined $projectDirectory)
        -                    {
        -                    push @errorMessages, 'You cannot have more than one project directory.';
        -                    $valueRef = \$ignored;
        -                    }
        -                else
        -                    {  $valueRef = \$projectDirectory;  };
        -                }
        -            elsif ($option eq '-o')
        -                {
        -                push @outputStrings, undef;
        -                $valueRef = \$outputStrings[-1];
        -                }
        -            elsif ($option eq '-s')
        -                {
        -                $valueRef = \$styles[0];
        -                }
        -            elsif ($option eq '-t')
        -                {
        -                $valueRef = \$tabLength;
        -                }
        -            elsif ($option eq '-hl')
        -            	{
        -            	$valueRef = \$highlightString;
        -            	}
        -            elsif ($option eq '-ag')
        -                {
        -                push @errorMessages, 'The -ag setting is no longer supported.  You can use -nag (--no-auto-group) to turn off '
        -                                               . "auto-grouping, but there aren't multiple levels anymore.";
        -                $valueRef = \$ignored;
        -                }
        -
        -            # Options that aren't followed by content.
        -            else
        -                {
        -                $valueRef = undef;
        -
        -                if ($option eq '-r')
        -                    {
        -                    NaturalDocs::Project->ReparseEverything();
        -                    NaturalDocs::Project->RebuildEverything();
        -                    $rebuildData = 1;
        -                    }
        -                elsif ($option eq '-ro')
        -                    {
        -                    NaturalDocs::Project->RebuildEverything();
        -                    }
        -                elsif ($option eq '-do')
        -                    {  $documentedOnly = 1;  }
        -                elsif ($option eq '-oft')
        -                    {  $onlyFileTitles = 1;  }
        -                elsif ($option eq '-q')
        -                    {  $isQuiet = 1;  }
        -                elsif ($option eq '-ho')
        -                    {
        -                    push @errorMessages, 'The -ho setting is no longer supported.  You can have Natural Docs skip over the source file '
        -                                                   . 'extensions by editing Languages.txt in your project directory.';
        -                    }
        -                elsif ($option eq '-nag')
        -                    {  $noAutoGroup = 1;  }
        -                elsif ($option eq '-?' || $option eq '-h')
        -                    {
        -                    $self->PrintSyntax();
        -                    exit;
        -                    }
        -                else
        -                    {  push @errorMessages, 'Unrecognized option ' . $option;  };
        -
        -                };
        -
        -            }
        -
        -        # Is a segment of text, not an option...
        -        else
        -            {
        -            if (defined $valueRef)
        -                {
        -                # We want to preserve spaces in paths.
        -                if (defined $$valueRef)
        -                    {  $$valueRef .= ' ';  };
        -
        -                $$valueRef .= $arg;
        -                }
        -
        -            else
        -                {
        -                push @errorMessages, 'Unrecognized element ' . $arg;
        -                };
        -            };
        -
        -        $index++;
        -        };
        -
        -
        -    # Validate the style, if specified.
        -
        -    if ($styles[0])
        -        {
        -        my @stylePieces = split(/ +/, $styles[0]);
        -        @styles = ( );
        -
        -        while (scalar @stylePieces)
        -            {
        -            if (lc($stylePieces[0]) eq 'custom')
        -                {
        -                push @errorMessages, 'The "Custom" style setting is no longer supported.  Copy your custom style sheet to your '
        -                                               . 'project directory and you can refer to it with -s.';
        -                shift @stylePieces;
        -                }
        -            else
        -                {
        -                # People may use styles with spaces in them.  If a style doesn't exist, we need to join the pieces until we find one that
        -                # does or we run out of pieces.
        -
        -                my $extras = 0;
        -                my $success;
        -
        -                while ($extras < scalar @stylePieces)
        -                    {
        -                    my $style;
        -
        -                    if (!$extras)
        -                        {  $style = $stylePieces[0];  }
        -                    else
        -                        {  $style = join(' ', @stylePieces[0..$extras]);  };
        -
        -                    my $cssFile = NaturalDocs::File->JoinPaths( $self->StyleDirectory(), $style . '.css' );
        -                    if (-e $cssFile)
        -                        {
        -                        push @styles, $style;
        -                        splice(@stylePieces, 0, 1 + $extras);
        -                        $success = 1;
        -                        last;
        -                        }
        -                    else
        -                        {
        -                        $cssFile = NaturalDocs::File->JoinPaths( $self->ProjectDirectory(), $style . '.css' );
        -
        -                        if (-e $cssFile)
        -                            {
        -                            push @styles, $style;
        -                            splice(@stylePieces, 0, 1 + $extras);
        -                            $success = 1;
        -                            last;
        -                            }
        -                        else
        -                            {  $extras++;  };
        -                        };
        -                    };
        -
        -                if (!$success)
        -                    {
        -                    push @errorMessages, 'The style "' . $stylePieces[0] . '" does not exist.';
        -                    shift @stylePieces;
        -                    };
        -                };
        -            };
        -        }
        -    else
        -        {  @styles = ( 'Default' );  };
        -
        -
        -    # Decode and validate the output strings.
        -
        -    my %outputDirectories;
        -
        -    foreach my $outputString (@outputStrings)
        -        {
        -        my ($format, $directory) = split(/ /, $outputString, 2);
        -
        -        if (!defined $directory)
        -            {  push @errorMessages, 'The -o option needs two parameters: -o [format] [directory]';  }
        -        else
        -            {
        -            if (!NaturalDocs::File->PathIsAbsolute($directory))
        -                {  $directory = NaturalDocs::File->JoinPaths(Cwd::cwd(), $directory, 1);  };
        -
        -            $directory = NaturalDocs::File->CanonizePath($directory);
        -
        -            if (! -e $directory || ! -d $directory)
        -                {
        -                # They may have forgotten the format portion and the directory name had a space in it.
        -                if (-e ($format . ' ' . $directory) && -d ($format . ' ' . $directory))
        -                    {
        -                    push @errorMessages, 'The -o option needs two parameters: -o [format] [directory]';
        -                    $format = undef;
        -                    }
        -                else
        -                    {  push @errorMessages, 'The output directory ' . $directory . ' does not exist.';  }
        -                }
        -            elsif (exists $outputDirectories{$directory})
        -                {  push @errorMessages, 'You cannot specify the output directory ' . $directory . ' more than once.';  }
        -            else
        -                {  $outputDirectories{$directory} = 1;  };
        -
        -            if (defined $format)
        -                {
        -                my $builderPackage = NaturalDocs::Builder->OutputPackageOf($format);
        -
        -                if (defined $builderPackage)
        -                    {
        -                    push @buildTargets,
        -                            NaturalDocs::Settings::BuildTarget->New($builderPackage->New(), $directory);
        -                    }
        -                else
        -                    {
        -                    push @errorMessages, 'The output format ' . $format . ' doesn\'t exist or is not installed.';
        -                    $valueRef = \$ignored;
        -                    };
        -                };
        -            };
        -        };
        -
        -    if (!scalar @buildTargets)
        -        {  push @errorMessages, 'You did not specify an output directory.';  };
        -
        -
        -    # Decode and validate the image strings.
        -
        -    foreach my $imageString (@imageStrings)
        -        {
        -        if ($imageString =~ /^ *\*/)
        -            {
        -            # The below NaturalDocs::File functions assume everything is canonized.
        -            $imageString = NaturalDocs::File->CanonizePath($imageString);
        -
        -            my ($volume, $directoryString) = NaturalDocs::File->SplitPath($imageString, 1);
        -            my @directories = NaturalDocs::File->SplitDirectories($directoryString);
        -
        -            shift @directories;
        -
        -            $directoryString = NaturalDocs::File->JoinDirectories(@directories);
        -            push @relativeImageDirectories, NaturalDocs::File->JoinPath($volume, $directoryString);
        -            }
        -        else
        -            {
        -            if (!NaturalDocs::File->PathIsAbsolute($imageString))
        -                {  $imageString = NaturalDocs::File->JoinPaths(Cwd::cwd(), $imageString, 1);  };
        -
        -            $imageString = NaturalDocs::File->CanonizePath($imageString);
        -
        -            if (! -e $imageString || ! -d $imageString)
        -                {  push @errorMessages, 'The image directory ' . $imageString . ' does not exist.';  };
        -
        -            push @imageDirectories, $imageString;
        -            };
        -        };
        -
        -
        -    # Make sure the input and project directories are specified, canonized, and exist.
        -
        -    if (scalar @inputDirectories)
        -        {
        -        for (my $i = 0; $i < scalar @inputDirectories; $i++)
        -            {
        -            if (!NaturalDocs::File->PathIsAbsolute($inputDirectories[$i]))
        -                {  $inputDirectories[$i] = NaturalDocs::File->JoinPaths(Cwd::cwd(), $inputDirectories[$i], 1);  };
        -
        -            $inputDirectories[$i] = NaturalDocs::File->CanonizePath($inputDirectories[$i]);
        -
        -            if (! -e $inputDirectories[$i] || ! -d $inputDirectories[$i])
        -                {  push @errorMessages, 'The input directory ' . $inputDirectories[$i] . ' does not exist.';  };
        -            };
        -        }
        -    else
        -        {  push @errorMessages, 'You did not specify an input (source) directory.';  };
        -
        -    if (defined $projectDirectory)
        -        {
        -        if (!NaturalDocs::File->PathIsAbsolute($projectDirectory))
        -            {  $projectDirectory = NaturalDocs::File->JoinPaths(Cwd::cwd(), $projectDirectory, 1);  };
        -
        -        $projectDirectory = NaturalDocs::File->CanonizePath($projectDirectory);
        -
        -        if (! -e $projectDirectory || ! -d $projectDirectory)
        -            {  push @errorMessages, 'The project directory ' . $projectDirectory . ' does not exist.';  };
        -
        -        # Create the Data subdirectory if it doesn't exist.
        -        NaturalDocs::File->CreatePath( NaturalDocs::File->JoinPaths($projectDirectory, 'Data', 1) );
        -        }
        -    else
        -        {  push @errorMessages, 'You did not specify a project directory.';  };
        -
        -
        -    # Make sure the excluded input directories are canonized, and add the project and output directories to the list.
        -
        -    for (my $i = 0; $i < scalar @excludedInputDirectories; $i++)
        -        {
        -        if (!NaturalDocs::File->PathIsAbsolute($excludedInputDirectories[$i]))
        -            {  $excludedInputDirectories[$i] = NaturalDocs::File->JoinPaths(Cwd::cwd(), $excludedInputDirectories[$i], 1);  };
        -
        -        $excludedInputDirectories[$i] = NaturalDocs::File->CanonizePath($excludedInputDirectories[$i]);
        -        };
        -
        -    push @excludedInputDirectories, $projectDirectory;
        -
        -    foreach my $buildTarget (@buildTargets)
        -        {
        -        push @excludedInputDirectories, $buildTarget->Directory();
        -        };
        -
        -
        -    # Determine the tab length, and default to four if not specified.
        -
        -    if (defined $tabLength)
        -        {
        -        if ($tabLength !~ /^[0-9]+$/)
        -            {  push @errorMessages, 'The tab length must be a number.';  };
        -        }
        -    else
        -        {  $tabLength = 4;  };
        -
        -
        -    # Decode and validate the highlight setting.
        -
        -    if (defined $highlightString)
        -    	{
        -    	$highlightString = lc($highlightString);
        -
        -    	if ($highlightString eq 'off')
        -    		{
        -    		$highlightCode = undef;
        -    		$highlightAnonymous = undef;
        -    		}
        -    	elsif ($highlightString eq 'code')
        -    		{
        -    		$highlightCode = 1;
        -    		$highlightAnonymous = undef;
        -    		}
        -    	elsif ($highlightString eq 'all')
        -    		{
        -    		$highlightCode = 1;
        -    		$highlightAnonymous = 1;
        -    		}
        -    	else
        -    		{  push @errorMessages, $highlightString . ' is not a valid value for --highlight.';  }
        -    	}
        -    else
        -    	{
        -    	$highlightCode = 1;
        -    	$highlightAnonymous = undef;
        -    	}
        -
        -
        -    # Exit with the error message if there was one.
        -
        -    if (scalar @errorMessages)
        -        {
        -        print join("\n", @errorMessages) . "\nType NaturalDocs -h to see the syntax reference.\n";
        -        exit;
        -        };
        -    };
        -
        -#
        -#   Function: PrintSyntax
        -#
        -#   Prints the syntax reference.
        -#
        -sub PrintSyntax
        -    {
        -    my ($self) = @_;
        -
        -    # Make sure all line lengths are under 80 characters.
        -
        -    print
        -
        -    "Natural Docs, version " . $self->TextAppVersion() . "\n"
        -    . $self->AppURL() . "\n"
        -    . "This program is licensed under version 3 of the AGPL\n"
        -    . "Refer to License.txt for the complete details\n"
        -    . "--------------------------------------\n"
        -    . "\n"
        -    . "Syntax:\n"
        -    . "\n"
        -    . "    NaturalDocs -i [input (source) directory]\n"
        -    . "               (-i [input (source) directory] ...)\n"
        -    . "                -o [output format] [output directory]\n"
        -    . "               (-o [output format] [output directory] ...)\n"
        -    . "                -p [project directory]\n"
        -    . "                [options]\n"
        -    . "\n"
        -    . "Examples:\n"
        -    . "\n"
        -    . "    NaturalDocs -i C:\\My Project\\Source -o HTML C:\\My Project\\Docs\n"
        -    . "                -p C:\\My Project\\Natural Docs\n"
        -    . "    NaturalDocs -i /src/project -o HTML /doc/project\n"
        -    . "                -p /etc/naturaldocs/project -s Small -q\n"
        -    . "\n"
        -    . "Required Parameters:\n"
        -    . "\n"
        -    . " -i [dir]\n--input [dir]\n--source [dir]\n"
        -    . "     Specifies an input (source) directory.  Required.\n"
        -    . "     Can be specified multiple times.\n"
        -    . "\n"
        -    . " -o [fmt] [dir]\n--output [fmt] [dir]\n"
        -    . "    Specifies an output format and directory.  Required.\n"
        -    . "    Can be specified multiple times, but only once per directory.\n"
        -    . "    Possible output formats:\n";
        -
        -    $self->PrintOutputFormats('    - ');
        -
        -    print
        -    "\n"
        -    . " -p [dir]\n--project [dir]\n"
        -    . "    Specifies the project directory.  Required.\n"
        -    . "    There needs to be a unique project directory for every source directory.\n"
        -    . "\n"
        -    . "Optional Parameters:\n"
        -    . "\n"
        -    . " -s [style] ([style] [style] ...)\n--style [style] ([style] [style] ...)\n"
        -    . "    Specifies the CSS style when building HTML output.  If multiple styles are\n"
        -    . "    specified, they will all be included in the order given.\n"
        -    . "\n"
        -    . " -img [image directory]\n--image [image directory]\n"
        -    . "    Specifies an image directory.  Can be specified multiple times.\n"
        -    . "    Start with * to specify a relative directory, as in -img */images.\n"
        -    . "\n"
        -    . " -do\n--documented-only\n"
        -    . "    Specifies only documented code aspects should be included in the output.\n"
        -    . "\n"
        -    . " -t [len]\n--tab-length [len]\n"
        -    . "    Specifies the number of spaces tabs should be expanded to.  This only needs\n"
        -    . "    to be set if you use tabs in example code and text diagrams.  Defaults to 4.\n"
        -    . "\n"
        -    . " -xi [dir]\n--exclude-input [dir]\n--exclude-source [dir]\n"
        -    . "    Excludes an input (source) directory from the documentation.\n"
        -    . "    Automatically done for the project and output directories.  Can\n"
        -    . "    be specified multiple times.\n"
        -    . "\n"
        -    . " -nag\n--no-auto-group\n"
        -    . "    Turns off auto-grouping completely.\n"
        -    . "\n"
        -    . " -oft\n--only-file-titles\n"
        -    . "    Source files will only use the file name as the title.\n"
        -    . "\n"
        -    . " -hl [option]\n--highlight [option]\n"
        -    . "    Specifies when syntax highlighting should be applied.  Defaults to code.\n"
        -    . "    off  - No syntax highlighting is applied.\n"
        -    . "    code - Syntax highlighting is only applied to prototypes and (start code)\n"
        -    . "           segments.\n"
        -    . "    all  - Systax highlighting is applied to prototypes, (start code) segments,\n"
        -    . "           and lines starting with >, :, or |."
        -    . "\n"
        -    . " -r\n--rebuild\n"
        -    . "    Rebuilds all output and data files from scratch.\n"
        -    . "    Does not affect the menu file.\n"
        -    . "\n"
        -    . " -ro\n--rebuild-output\n"
        -    . "    Rebuilds all output files from scratch.\n"
        -    . "\n"
        -    . " -q\n--quiet\n"
        -    . "    Suppresses all non-error output.\n"
        -    . "\n"
        -    . " -?\n -h\n--help\n"
        -    . "    Displays this syntax reference.\n";
        -    };
        -
        -
        -#
        -#   Function: PrintOutputFormats
        -#
        -#   Prints all the possible output formats that can be specified with -o.  Each one will be placed on its own line.
        -#
        -#   Parameters:
        -#
        -#       prefix - Characters to prefix each one with, such as for indentation.
        -#
        -sub PrintOutputFormats #(prefix)
        -    {
        -    my ($self, $prefix) = @_;
        -
        -    my $outputPackages = NaturalDocs::Builder::OutputPackages();
        -
        -    foreach my $outputPackage (@$outputPackages)
        -        {
        -        print $prefix . $outputPackage->CommandLineOption() . "\n";
        -        };
        -    };
        -
        -
        -#
        -#   Function: LoadAndComparePreviousSettings
        -#
        -#   Loads <PreviousSettings.nd> and compares the values there with those in the command line.  If differences require it,
        -#   sets <rebuildData> and/or <rebuildOutput>.
        -#
        -sub LoadAndComparePreviousSettings
        -    {
        -    my ($self) = @_;
        -
        -    my $fileIsOkay;
        -
        -    if (!NaturalDocs::Settings->RebuildData())
        -        {
        -        my $version;
        -
        -        if (NaturalDocs::BinaryFile->OpenForReading( NaturalDocs::Project->DataFile('PreviousSettings.nd'),
        -                                                                           NaturalDocs::Version->FromString('1.51') ))
        -            {  $fileIsOkay = 1;  };
        -        };
        -
        -    if (!$fileIsOkay)
        -        {
        -        # We need to reparse everything because --documented-only may have changed.
        -        # We need to rebuild everything because --tab-length may have changed.
        -        NaturalDocs::Project->ReparseEverything();
        -        NaturalDocs::Project->RebuildEverything();
        -        }
        -    else
        -        {
        -        my $raw;
        -
        -        # [UInt8: tab expansion]
        -        # [UInt8: documented only (0 or 1)]
        -        # [UInt8: no auto-group (0 or 1)]
        -        # [UInt8: only file titles (0 or 1)]
        -        # [UInt8: highlight code (0 or 1)]
        -        # [UInt8: highlight anonymous (0 or 1)]
        -
        -        my $prevTabLength = NaturalDocs::BinaryFile->GetUInt8();
        -        my $prevDocumentedOnly = NaturalDocs::BinaryFile->GetUInt8();
        -        my $prevNoAutoGroup = NaturalDocs::BinaryFile->GetUInt8();
        -        my $prevOnlyFileTitles = NaturalDocs::BinaryFile->GetUInt8();
        -        my $prevHighlightCode = NaturalDocs::BinaryFile->GetUInt8();
        -        my $prevHighlightAnonymous = NaturalDocs::BinaryFile->GetUInt8();
        -
        -        if ($prevDocumentedOnly == 0)
        -            {  $prevDocumentedOnly = undef;  };
        -        if ($prevNoAutoGroup == 0)
        -            {  $prevNoAutoGroup = undef;  };
        -        if ($prevOnlyFileTitles == 0)
        -            {  $prevOnlyFileTitles = undef;  };
        -        if ($prevHighlightCode == 0)
        -            {  $prevHighlightCode = undef;  };
        -        if ($prevHighlightAnonymous == 0)
        -            {  $prevHighlightAnonymous = undef;  };
        -
        -        if ($prevTabLength != $self->TabLength() ||
        -        	$prevHighlightCode != $self->HighlightCode() ||
        -        	$prevHighlightAnonymous != $self->HighlightAnonymous())
        -            {
        -            NaturalDocs::Project->RebuildEverything();
        -            };
        -
        -        if ($prevDocumentedOnly != $self->DocumentedOnly() ||
        -            $prevNoAutoGroup != $self->NoAutoGroup() ||
        -            $prevOnlyFileTitles != $self->OnlyFileTitles())
        -            {
        -            NaturalDocs::Project->ReparseEverything();
        -            };
        -
        -
        -        # [UInt8: number of input directories]
        -
        -        my $inputDirectoryCount = NaturalDocs::BinaryFile->GetUInt8();
        -
        -        while ($inputDirectoryCount)
        -            {
        -            # [AString16: input directory] [AString16: input directory name] ...
        -
        -            my $inputDirectory = NaturalDocs::BinaryFile->GetAString16();
        -            my $inputDirectoryName = NaturalDocs::BinaryFile->GetAString16();
        -
        -            # Not doing anything with this for now.
        -
        -            $inputDirectoryCount--;
        -            };
        -
        -
        -        # [UInt8: number of output targets]
        -
        -        my $outputTargetCount = NaturalDocs::BinaryFile->GetUInt8();
        -
        -        # Keys are the directories, values are the command line options.
        -        my %previousOutputDirectories;
        -
        -        while ($outputTargetCount)
        -            {
        -            # [AString16: output directory] [AString16: output format command line option] ...
        -
        -            my $outputDirectory = NaturalDocs::BinaryFile->GetAString16();
        -            my $outputCommand = NaturalDocs::BinaryFile->GetAString16();
        -
        -            $previousOutputDirectories{$outputDirectory} = $outputCommand;
        -
        -            $outputTargetCount--;
        -            };
        -
        -        # Check if any targets were added to the command line, or if their formats changed.  We don't care if targets were
        -        # removed.
        -        my $buildTargets = $self->BuildTargets();
        -
        -        foreach my $buildTarget (@$buildTargets)
        -            {
        -            if (!exists $previousOutputDirectories{$buildTarget->Directory()} ||
        -                $buildTarget->Builder()->CommandLineOption() ne $previousOutputDirectories{$buildTarget->Directory()})
        -                {
        -                NaturalDocs::Project->RebuildEverything();
        -                last;
        -                };
        -            };
        -
        -        NaturalDocs::BinaryFile->Close();
        -        };
        -    };
        -
        -
        -#
        -#   Function: SavePreviousSettings
        -#
        -#   Saves the settings into <PreviousSettings.nd>.
        -#
        -sub SavePreviousSettings
        -    {
        -    my ($self) = @_;
        -
        -    NaturalDocs::BinaryFile->OpenForWriting(  NaturalDocs::Project->DataFile('PreviousSettings.nd') );
        -
        -    # [UInt8: tab length]
        -    # [UInt8: documented only (0 or 1)]
        -    # [UInt8: no auto-group (0 or 1)]
        -    # [UInt8: only file titles (0 or 1)]
        -    # [UInt8: highlight code (0 or 1)]
        -    # [UInt8: highlight anonymous (0 or 1)]
        -    # [UInt8: number of input directories]
        -
        -    my $inputDirectories = $self->InputDirectories();
        -
        -    NaturalDocs::BinaryFile->WriteUInt8($self->TabLength());
        -    NaturalDocs::BinaryFile->WriteUInt8($self->DocumentedOnly() ? 1 : 0);
        -    NaturalDocs::BinaryFile->WriteUInt8($self->NoAutoGroup() ? 1 : 0);
        -    NaturalDocs::BinaryFile->WriteUInt8($self->OnlyFileTitles() ? 1 : 0);
        -    NaturalDocs::BinaryFile->WriteUInt8($self->HighlightCode() ? 1 : 0);
        -    NaturalDocs::BinaryFile->WriteUInt8($self->HighlightAnonymous() ? 1 : 0);
        -    NaturalDocs::BinaryFile->WriteUInt8(scalar @$inputDirectories);
        -
        -    foreach my $inputDirectory (@$inputDirectories)
        -        {
        -        my $inputDirectoryName = $self->InputDirectoryNameOf($inputDirectory);
        -
        -        # [AString16: input directory] [AString16: input directory name] ...
        -        NaturalDocs::BinaryFile->WriteAString16($inputDirectory);
        -        NaturalDocs::BinaryFile->WriteAString16($inputDirectoryName);
        -        };
        -
        -    # [UInt8: number of output targets]
        -
        -    my $buildTargets = $self->BuildTargets();
        -    NaturalDocs::BinaryFile->WriteUInt8(scalar @$buildTargets);
        -
        -    foreach my $buildTarget (@$buildTargets)
        -        {
        -        # [AString16: output directory] [AString16: output format command line option] ...
        -        NaturalDocs::BinaryFile->WriteAString16( $buildTarget->Directory() );
        -        NaturalDocs::BinaryFile->WriteAString16( $buildTarget->Builder()->CommandLineOption() );
        -        };
        -
        -    NaturalDocs::BinaryFile->Close();
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Settings/BuildTarget.pm b/vendor/naturaldocs/Modules/NaturalDocs/Settings/BuildTarget.pm
        deleted file mode 100644
        index 81595757e..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Settings/BuildTarget.pm
        +++ /dev/null
        @@ -1,67 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::Settings::BuildTarget
        -#
        -###############################################################################
        -#
        -#   A class that stores information about a build target.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Settings::BuildTarget;
        -
        -use NaturalDocs::DefineMembers 'BUILDER', 'Builder()', 'SetBuilder()',
        -                                                 'DIRECTORY', 'Directory()', 'SetDirectory()';
        -
        -
        -#
        -#   Constants: Members
        -#
        -#   The class is implemented as a blessed arrayref with the members below.
        -#
        -#       BUILDER      - The <NaturalDocs::Builder::Base>-derived object for the target's output format.
        -#       DIRECTORY - The output directory of the target.
        -#
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -#   Parameters:
        -#
        -#       builder - The <NaturalDocs::Builder::Base>-derived object for the target's output format.
        -#       directory - The directory to place the output files in.
        -#
        -sub New #(builder, directory)
        -    {
        -    my ($package, $builder, $directory) = @_;
        -
        -    my $object = [ ];
        -    bless $object, $package;
        -
        -    $object->SetBuilder($builder);
        -    $object->SetDirectory($directory);
        -
        -    return $object;
        -    };
        -
        -
        -#
        -#   Functions: Member Functions
        -#
        -#   Builder - Returns the <NaturalDocs::Builder::Base>-derived object for the target's output format.
        -#   SetBuilder - Replaces the <NaturalDocs::Builder::Base>-derived object for the target's output format.
        -#   Directory - Returns the directory for the target's output files.
        -#   SetDirectory - Replaces the directory for the target's output files.
        -#
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/SourceDB.pm b/vendor/naturaldocs/Modules/NaturalDocs/SourceDB.pm
        deleted file mode 100644
        index 773aadc0b..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/SourceDB.pm
        +++ /dev/null
        @@ -1,679 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::SourceDB
        -#
        -###############################################################################
        -#
        -#   SourceDB is an experimental package meant to unify the tracking of various elements in the source code.
        -#
        -#   Requirements:
        -#
        -#       - All extension packages must call <RegisterExtension()> before they can be used.
        -#
        -#
        -#   Architecture: The Idea
        -#
        -#       For quite a while Natural Docs only needed <SymbolTable>.  However, 1.3 introduced the <ClassHierarchy> package
        -#       which duplicated some of its functionality to track classes and parent references.  1.4 now needs <ImageReferenceTable>,
        -#       so this package was an attempt to isolate the common functionality so the wheel doesn't have to keep being rewritten as
        -#       the scope of Natural Docs expands.
        -#
        -#       SourceDB is designed around <Extensions> and items.  The purposefully vague "items" are anything in the source code
        -#       that we need to track the definitions of.  Extensions are the packages to track them, only they're derived from
        -#       <NaturalDocs::SourceDB::Extension> and registered with this package instead of being free standing and duplicating
        -#       functionality such as watched files.
        -#
        -#       The architecture on this package isn't comprehensive yet.  As more extensions are added or previously made free standing
        -#       packages are migrated to it it will expand to encompass them.  However, it's still experimental so this concept may
        -#       eventually be abandoned for something better instead.
        -#
        -#
        -#   Architecture: Assumptions
        -#
        -#       SourceDB is built around certain assumptions.
        -#
        -#       One item per file:
        -#
        -#           SourceDB assumes that only the first item per file with a particular item string is relevant.  For example, if two functions
        -#           have the exact same name, there's no way to link to the second one either in HTML or internally so it doesn't matter for
        -#           our purposes.  Likewise, if two references are exactly the same they go to the same target, so it doesn't matter whether
        -#           there's one or two or a thousand.  All that matters is that at least one reference exists in this file because you only need
        -#           to determine whether the entire file gets rebuilt.  If two items are different in some meaningful way, they should generate
        -#           different item strings.
        -#
        -#       Watched file parsing:
        -#
        -#           SourceDB assumes the parse method is that the information that was stored from Natural Docs' previous run is loaded, a
        -#           file is watched, that file is reparsed, and then <AnalyzeWatchedFileChanges()> is called.  When the file is reparsed all
        -#           items within it are added the same as if the file was never parsed before.
        -#
        -#           If there's a new item this time around, that's fine no matter what.  However, a changed item wouldn't normally be
        -#           recorded because the previous run's definition is seen as the first one and subsequent ones are ignored.  Also, deleted
        -#           items would normally not be recorded either because we're only adding.
        -#
        -#           The watched file method fixes this because everything is also added to a second, clean database specifically for the
        -#           watched file.  Because it starts clean, it always gets the first definition from the current parse which can then be
        -#           compared to the original by <AnalyzeWatchedFileChanges()>.  Because it starts clean you can also compare it to the
        -#           main database to see if anything was deleted, because it would appear in the main database but not the watched one.
        -#
        -#           This means that functions like <ChangeDefinition()> and <DeleteDefinition()> should only be called by
        -#           <AnalyzeWatchedFileChanges()>.  Externally only <AddDefinition()> should be called.  <DeleteItem()> is okay to be
        -#           called externally because entire items aren't managed by the watched file database, only definitions.
        -#
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -
        -use NaturalDocs::SourceDB::Extension;
        -use NaturalDocs::SourceDB::Item;
        -use NaturalDocs::SourceDB::ItemDefinition;
        -use NaturalDocs::SourceDB::File;
        -use NaturalDocs::SourceDB::WatchedFileDefinitions;
        -
        -
        -package NaturalDocs::SourceDB;
        -
        -
        -###############################################################################
        -# Group: Types
        -
        -
        -#
        -#   Type: ExtensionID
        -#
        -#   A unique identifier for each <NaturalDocs::SourceDB> extension as given out by <RegisterExtension()>.
        -#
        -
        -
        -
        -###############################################################################
        -# Group: Variables
        -
        -
        -#
        -#   array: extensions
        -#
        -#   An array of <NaturalDocs::SourceDB::Extension>-derived extensions, as added with <RegisterExtension()>.  The indexes
        -#   are the <ExtensionIDs> and the values are package references.
        -#
        -my @extensions;
        -
        -#
        -#   array: extensionUsesDefinitionObjects
        -#
        -#   An array where the indexes are <ExtensionIDs> and the values are whether that extension uses its own definition class
        -#   derived from <NaturalDocs::SourceDB::ItemDefinition> or it just tracks their existence.
        -#
        -my @extensionUsesDefinitionObjects;
        -
        -
        -
        -#
        -#   array: items
        -#
        -#   The array of source items.  The <ExtensionIDs> are the indexes, and the values are hashrefs mapping the item
        -#   string to <NaturalDocs::SourceDB::Item>-derived objects.  Hashrefs may be undef.
        -#
        -my @items;
        -
        -
        -#
        -#   hash: files
        -#
        -#   A hashref mapping source <FileNames> to <NaturalDocs::SourceDB::Files>.
        -#
        -my %files;
        -
        -
        -#
        -#   object: watchedFile
        -#
        -#   When a file is being watched for changes, will be a <NaturalDocs::SourceDB::File> for that file.  Is undef otherwise.
        -#
        -#   When the file is parsed, items are added to both this and the version in <files>.  Thus afterwards we can compare the two to
        -#   see if any were deleted since the last time Natural Docs was run, because they would be in the <files> version but not this
        -#   one.
        -#
        -my $watchedFile;
        -
        -
        -#
        -#   string: watchedFileName
        -#
        -#   When a file is being watched for changes, will be the <FileName> of the file being watched.  Is undef otherwise.
        -#
        -my $watchedFileName;
        -
        -
        -#
        -#   object: watchedFileDefinitions
        -#
        -#   When a file is being watched for changes, will be a <NaturalDocs::SourceDB::WatchedFileDefinitions> object.  Is undef
        -#   otherwise.
        -#
        -#   When the file is parsed, items are added to both this and the version in <items>.  Since only the first definition is kept, this
        -#   will always have the definition info from the file whereas the version in <items> will have the first definition as of the last time
        -#   Natural Docs was run.  Thus they can be compared to see if the definitions of items that existed the last time around have
        -#   changed.
        -#
        -my $watchedFileDefinitions;
        -
        -
        -
        -###############################################################################
        -# Group: Extension Functions
        -
        -
        -#
        -#   Function: RegisterExtension
        -#
        -#   Registers a <NaturalDocs::SourceDB::Extension>-derived package and returns a unique <ExtensionID> for it.  All extensions
        -#   must call this before they can be used.
        -#
        -#   Registration Order:
        -#
        -#       The order in which extensions register is important.  Whenever possible, items are added in the order their extensions
        -#       registered.  However, items are changed and deleted in the reverse order.  Take advantage of this to minimize
        -#       churn between extensions that are dependent on each other.
        -#
        -#       For example, when symbols are added or deleted they may cause references to be retargeted and thus their files need to
        -#       be rebuilt.  However, adding or deleting references never causes the symbols' files to be rebuilt.  So it makes sense that
        -#       symbols should be created before references, and that references should be deleted before symbols.
        -#
        -#   Parameters:
        -#
        -#       extension - The package or object of the extension.  Must be derived from <NaturalDocs::SourceDB::Extension>.
        -#       usesDefinitionObjects - Whether the extension uses its own class derived from <NaturalDocs::SourceDB::ItemDefinition>
        -#                                         or simply tracks each definitions existence.
        -#
        -#   Returns:
        -#
        -#       An <ExtensionID> unique to the extension.  This should be saved because it's required in functions such as <AddItem()>.
        -#
        -sub RegisterExtension #(package extension, bool usesDefinitionObjects) => ExtensionID
        -    {
        -    my ($self, $extension, $usesDefinitionObjects) = @_;
        -
        -    push @extensions, $extension;
        -    push @extensionUsesDefinitionObjects, $usesDefinitionObjects;
        -
        -    return scalar @extensions - 1;
        -    };
        -
        -
        -
        -
        -###############################################################################
        -# Group: File Functions
        -
        -
        -#
        -#   Function: Load
        -#
        -#   Loads the data of the source database and all the extensions.  Will call <NaturalDocs::SourceDB::Extension->Load()> for
        -#   all of them, unless there's a situation where all the source files are going to be reparsed anyway in which case it's not needed.
        -#
        -sub Load
        -    {
        -    my $self = shift;
        -
        -    # No point loading if RebuildData is set.
        -    if (!NaturalDocs::Settings->RebuildData())
        -        {
        -        # If any load fails, stop loading the rest and just reparse all the source files.
        -        my $success = 1;
        -
        -        for (my $extension = 0; $extension < scalar @extensions && $success; $extension++)
        -            {
        -            $success = $extensions[$extension]->Load();
        -            };
        -
        -        if (!$success)
        -            {  NaturalDocs::Project->ReparseEverything();  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: Save
        -#
        -#   Saves the data of the source database and all its extensions.  Will call <NaturalDocs::SourceDB::Extension->Save()> for all
        -#   of them.
        -#
        -sub Save
        -    {
        -    my $self = shift;
        -
        -    for (my $extension = scalar @extensions - 1; $extension >= 0; $extension--)
        -        {
        -        $extensions[$extension]->Save();
        -        };
        -    };
        -
        -
        -#
        -#   Function: PurgeDeletedSourceFiles
        -#
        -#   Removes all data associated with deleted source files.
        -#
        -sub PurgeDeletedSourceFiles
        -    {
        -    my $self = shift;
        -
        -    my $filesToPurge = NaturalDocs::Project->FilesToPurge();
        -
        -    # Extension is the outermost loop because we want the extensions added last to have their definitions removed first to cause
        -    # the least amount of churn between interdependent extensions.
        -    for (my $extension = scalar @extensions - 1; $extension >= 0; $extension--)
        -        {
        -        foreach my $file (keys %$filesToPurge)
        -            {
        -            if (exists $files{$file})
        -                {
        -                my @items = $files{$file}->ListItems($extension);
        -
        -                foreach my $item (@items)
        -                    {
        -                    $self->DeleteDefinition($extension, $item, $file);
        -                    };
        -                }; # file exists
        -            }; # each file
        -        }; # each extension
        -    };
        -
        -
        -
        -
        -
        -###############################################################################
        -# Group: Item Functions
        -
        -
        -#
        -#   Function: AddItem
        -#
        -#   Adds the passed item to the database.  This will not work if the item string already exists.  The item added should *not*
        -#   already have definitions attached.  Only use this to add blank items and then call <AddDefinition()> instead.
        -#
        -#   Parameters:
        -#
        -#       extension - An <ExtensionID>.
        -#       itemString - The string serving as the item identifier.
        -#       item - An object derived from <NaturalDocs::SourceDB::Item>.
        -#
        -#   Returns:
        -#
        -#       Whether the item was added, that is, whether it was the first time this item was added.
        -#
        -sub AddItem #(ExtensionID extension, string itemString, NaturalDocs::SourceDB::Item item) => bool
        -    {
        -    my ($self, $extension, $itemString, $item) = @_;
        -
        -    if (!defined $items[$extension])
        -        {  $items[$extension] = { };  };
        -
        -    if (!exists $items[$extension]->{$itemString})
        -        {
        -        if ($item->HasDefinitions())
        -            {  die "Tried to add an item to SourceDB that already had definitions.";  };
        -
        -        $items[$extension]->{$itemString} = $item;
        -        return 1;
        -        };
        -
        -    return 0;
        -    };
        -
        -
        -#
        -#   Function: GetItem
        -#
        -#   Returns the <NaturalDocs::SourceDB::Item>-derived object for the passed <ExtensionID> and item string, or undef if there
        -#   is none.
        -#
        -sub GetItem #(ExtensionID extension, string itemString) => bool
        -    {
        -    my ($self, $extensionID, $itemString) = @_;
        -
        -    if (defined $items[$extensionID])
        -        {  return $items[$extensionID]->{$itemString};  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: DeleteItem
        -#
        -#   Deletes the record of the passed <ExtensionID> and item string.  Do *not* delete items that still have definitions.  Use
        -#   <DeleteDefinition()> first.
        -#
        -#   Parameters:
        -#
        -#       extension - The <ExtensionID>.
        -#       itemString - The item's identifying string.
        -#
        -#   Returns:
        -#
        -#       Whether it was successful, meaning whether an entry existed for it.
        -#
        -sub DeleteItem #(ExtensionID extension, string itemString) => bool
        -    {
        -    my ($self, $extension, $itemString) = @_;
        -
        -    if (defined $items[$extension] && exists $items[$extension]->{$itemString})
        -        {
        -        if ($items[$extension]->{$itemString}->HasDefinitions())
        -            {  die "Tried to delete an item from SourceDB that still has definitions.";  };
        -
        -        delete $items[$extension]->{$itemString};
        -        return 1;
        -        }
        -    else
        -        {  return 0;  };
        -    };
        -
        -
        -#
        -#   Function: HasItem
        -#
        -#   Returns whether there is an item defined for the passed <ExtensionID> and item string.
        -#
        -sub HasItem #(ExtensionID extension, string itemString) => bool
        -    {
        -    my ($self, $extension, $itemString) = @_;
        -
        -    if (defined $items[$extension])
        -        {  return (exists $items[$extension]->{$itemString});  }
        -    else
        -        {  return 0;  };
        -    };
        -
        -
        -#
        -#   Function: GetAllItemsHashRef
        -#
        -#   Returns a hashref of all the items defined for an extension.  *Do not change the contents.*  The keys are the item strings and
        -#   the values are <NaturalDocs::SourceDB::Items> or derived classes.
        -#
        -sub GetAllItemsHashRef #(ExtensionID extension) => hashref
        -    {
        -    my ($self, $extension) = @_;
        -    return $items[$extension];
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Definition Functions
        -
        -
        -#
        -#   Function: AddDefinition
        -#
        -#   Adds a definition to an item.  Assumes the item was already created with <AddItem()>.  If there's already a definition for this
        -#   file in the item, the new definition will be ignored.
        -#
        -#   Parameters:
        -#
        -#       extension - The <ExtensionID>.
        -#       itemString - The item string.
        -#       file - The <FileName> the definition is in.
        -#       definition - If you're using a custom <NaturalDocs::SourceDB::ItemDefinition> class, you must include an object for it here.
        -#                       Otherwise this parameter is ignored.
        -#
        -#   Returns:
        -#
        -#       Whether the definition was added, which is to say, whether this was the first definition for the passed <FileName>.
        -#
        -sub AddDefinition #(ExtensionID extension, string itemString, FileName file, optional NaturalDocs::SourceDB::ItemDefinition definition) => bool
        -    {
        -    my ($self, $extension, $itemString, $file, $definition) = @_;
        -
        -
        -    # Items
        -
        -    my $item = $self->GetItem($extension, $itemString);
        -
        -    if (!defined $item)
        -        {  die "Tried to add a definition to an undefined item in SourceDB.";  };
        -
        -    if (!$extensionUsesDefinitionObjects[$extension])
        -        {  $definition = 1;  };
        -
        -    my $result = $item->AddDefinition($file, $definition);
        -
        -
        -    # Files
        -
        -    if (!exists $files{$file})
        -        {  $files{$file} = NaturalDocs::SourceDB::File->New();  };
        -
        -    $files{$file}->AddItem($extension, $itemString);
        -
        -
        -    # Watched File
        -
        -    if ($self->WatchingFileForChanges())
        -        {
        -        $watchedFile->AddItem($extension, $itemString);
        -
        -        if ($extensionUsesDefinitionObjects[$extension])
        -            {  $watchedFileDefinitions->AddDefinition($extension, $itemString, $definition);  };
        -        };
        -
        -
        -    return $result;
        -    };
        -
        -
        -#
        -#   Function: ChangeDefinition
        -#
        -#   Changes the definition of an item.  This function is only used for extensions that use custom
        -#   <NaturalDocs::SourceDB::ItemDefinition>-derived classes.
        -#
        -#   Parameters:
        -#
        -#       extension - The <ExtensionID>.
        -#       itemString - The item string.
        -#       file - The <FileName> the definition is in.
        -#       definition - The definition, which must be an object derived from <NaturalDocs::SourceDB::ItemDefinition>.
        -#
        -sub ChangeDefinition #(ExtensionID extension, string itemString, FileName file, NaturalDocs::SourceDB::ItemDefinition definition)
        -    {
        -    my ($self, $extension, $itemString, $file, $definition) = @_;
        -
        -    my $item = $self->GetItem($extension, $itemString);
        -
        -    if (!defined $item)
        -        {  die "Tried to change the definition of an undefined item in SourceDB.";  };
        -
        -    if (!$extensionUsesDefinitionObjects[$extension])
        -        {  die "Tried to change the definition of an item in an extension that doesn't use definition objects in SourceDB.";  };
        -
        -    if (!$item->HasDefinition($file))
        -        {  die "Tried to change a definition that doesn't exist in SourceDB.";  };
        -
        -    $item->ChangeDefinition($file, $definition);
        -    $extensions[$extension]->OnChangedDefinition($itemString, $file);
        -    };
        -
        -
        -#
        -#   Function: GetDefinition
        -#
        -#   If the extension uses custom <NaturalDocs::SourceDB::ItemDefinition> classes, returns it for the passed definition or undef
        -#   if it doesn't exist.  Otherwise returns whether it exists.
        -#
        -sub GetDefinition #(ExtensionID extension, string itemString, FileName file) => NaturalDocs::SourceDB::ItemDefinition or bool
        -    {
        -    my ($self, $extension, $itemString, $file) = @_;
        -
        -    my $item = $self->GetItem($extension, $itemString);
        -
        -    if (!defined $item)
        -        {  return undef;  };
        -
        -    return $item->GetDefinition($file);
        -    };
        -
        -
        -#
        -#   Function: DeleteDefinition
        -#
        -#   Removes the definition for the passed item.  Returns whether it was successful, meaning whether a definition existed for that
        -#   file.
        -#
        -sub DeleteDefinition #(ExtensionID extension, string itemString, FileName file) => bool
        -    {
        -    my ($self, $extension, $itemString, $file) = @_;
        -
        -    my $item = $self->GetItem($extension, $itemString);
        -
        -    if (!defined $item)
        -        {  return 0;  };
        -
        -    my $result = $item->DeleteDefinition($file);
        -
        -    if ($result)
        -        {
        -        $files{$file}->DeleteItem($extension, $itemString);
        -        $extensions[$extension]->OnDeletedDefinition($itemString, $file, !$item->HasDefinitions());
        -        };
        -
        -    return $result;
        -    };
        -
        -
        -#
        -#   Function: HasDefinitions
        -#
        -#   Returns whether there are any definitions for this item.
        -#
        -sub HasDefinitions #(ExtensionID extension, string itemString) => bool
        -    {
        -    my ($self, $extension, $itemString) = @_;
        -
        -    my $item = $self->GetItem($extension, $itemString);
        -
        -    if (!defined $item)
        -        {  return 0;  };
        -
        -    return $item->HasDefinitions();
        -    };
        -
        -
        -#
        -#   Function: HasDefinition
        -#
        -#   Returns whether there is a definition for the passed <FileName>.
        -#
        -sub HasDefinition #(ExtensionID extension, string itemString, FileName file) => bool
        -    {
        -    my ($self, $extension, $itemString, $file) = @_;
        -
        -    my $item = $self->GetItem($extension, $itemString);
        -
        -    if (!defined $item)
        -        {  return 0;  };
        -
        -    return $item->HasDefinition($file);
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Watched File Functions
        -
        -
        -#
        -#   Function: WatchFileForChanges
        -#
        -#   Begins watching a file for changes.  Only one file at a time can be watched.
        -#
        -#   This should be called before a file is parsed so the file info goes both into the main database and the watched file info.
        -#   Afterwards you call <AnalyzeWatchedFileChanges()> so item deletions and definition changes can be detected.
        -#
        -#   Parameters:
        -#
        -#       filename - The <FileName> to watch.
        -#
        -sub WatchFileForChanges #(FileName filename)
        -    {
        -    my ($self, $filename) = @_;
        -
        -    $watchedFileName = $filename;
        -    $watchedFile = NaturalDocs::SourceDB::File->New();
        -    $watchedFileDefinitions = NaturalDocs::SourceDB::WatchedFileDefinitions->New();
        -    };
        -
        -
        -#
        -#   Function: WatchingFileForChanges
        -#
        -#   Returns whether we're currently watching a file for changes or not.
        -#
        -sub WatchingFileForChanges # => bool
        -    {
        -    my $self = shift;
        -    return defined $watchedFileName;
        -    };
        -
        -
        -#
        -#   Function: AnalyzeWatchedFileChanges
        -#
        -#   Analyzes the watched file for changes.  Will delete and change definitions as necessary.
        -#
        -sub AnalyzeWatchedFileChanges
        -    {
        -    my $self = shift;
        -
        -    if (!$self->WatchingFileForChanges())
        -        {  die "Tried to analyze watched file for changes in SourceDB when no file was being watched.";  };
        -    if (!$files{$watchedFileName})
        -        {  return;  };
        -
        -
        -    # Process extensions last registered to first.
        -
        -    for (my $extension = scalar @extensions - 1; $extension >= 0; $extension--)
        -        {
        -        my @items = $files{$watchedFileName}->ListItems($extension);
        -
        -        foreach my $item (@items)
        -            {
        -            if ($watchedFile->HasItem($extension, $item))
        -                {
        -                if ($extensionUsesDefinitionObjects[$extension])
        -                    {
        -                    my $originalDefinition = $items[$extension]->GetDefinition($watchedFileName);
        -                    my $watchedDefinition = $watchedFileDefinitions->GetDefinition($extension, $item);
        -
        -                    if (!$originalDefinition->Compare($watchedDefinition))
        -                        {  $self->ChangeDefinition($extension, $item, $watchedFileName, $watchedDefinition);  };
        -                    }
        -                }
        -            else # !$watchedFile->HasItem($item)
        -                {
        -                $self->DeleteDefinition($extension, $item, $watchedFileName);
        -                };
        -            };
        -        };
        -
        -
        -    $watchedFile = undef;
        -    $watchedFileName = undef;
        -    $watchedFileDefinitions = undef;
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/Extension.pm b/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/Extension.pm
        deleted file mode 100644
        index d610b24be..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/Extension.pm
        +++ /dev/null
        @@ -1,85 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::SourceDB::Extension
        -#
        -###############################################################################
        -#
        -#   A base package for all <SourceDB> extensions.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -
        -package NaturalDocs::SourceDB::Extension;
        -
        -
        -###############################################################################
        -# Group: Interface Functions
        -# These functions must be overridden by the derived class.
        -
        -
        -#
        -#   Function: Register
        -#
        -#   Override this function to register the package with <NaturalDocs::SourceDB->RegisterExtension()>.
        -#
        -sub Register
        -    {
        -    die "Called SourceDB::Extension->Register().  This function should be overridden by every extension.";
        -    };
        -
        -
        -#
        -#   Function: Load
        -#
        -#   Called by <NaturalDocs::SourceDB->Load()> to load the extension's data.  Returns whether it was successful.
        -#
        -#   *This function might not be called.*  If there's a situation that would cause all the source files to be reparsed anyway,
        -#   <NaturalDocs::SourceDB> may skip calling Load() for the remaining extensions.  You should *not* depend on this function
        -#   for any critical initialization that needs to happen every time regardless.
        -#
        -sub Load # => bool
        -    {
        -    return 1;
        -    };
        -
        -
        -#
        -#   Function: Save
        -#
        -#   Called by <NaturalDocs::SourceDB->Save()> to save the extension's data.
        -#
        -sub Save
        -    {
        -    };
        -
        -
        -#
        -#   Function: OnDeletedDefinition
        -#
        -#   Called for each definition deleted by <NaturalDocs::SourceDB>.  This is called *after* the definition has been deleted from
        -#   the database, so don't expect to be able to read it.
        -#
        -sub OnDeletedDefinition #(string itemString, FileName file, bool wasLastDefinition)
        -    {
        -    };
        -
        -
        -#
        -#   Function: OnChangedDefinition
        -#
        -#   Called for each definition changed by <NaturalDocs::SourceDB>.  This is called *after* the definition has been changed, so
        -#   don't expect to be able to read the original value.
        -#
        -sub OnChangedDefinition #(string itemString, FileName file)
        -    {
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/File.pm b/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/File.pm
        deleted file mode 100644
        index 1a4419fd2..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/File.pm
        +++ /dev/null
        @@ -1,130 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::SourceDB::File
        -#
        -###############################################################################
        -#
        -#   A class used to index items by file.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -
        -package NaturalDocs::SourceDB::File;
        -
        -use NaturalDocs::DefineMembers 'ITEMS';
        -
        -
        -#
        -#   Variables: Members
        -#
        -#   These constants serve as indexes into the object array.
        -#
        -#   ITEMS - An arrayref where an <ExtensionID> is the index and the members are existence hashrefs of the item strigs defined
        -#               in this file.  The arrayref will always exist, but the hashrefs may be undef.
        -#
        -
        -
        -#
        -#   Function: New
        -#
        -#   Returns a new object.
        -#
        -sub New
        -    {
        -    my $package = shift;
        -
        -    my $object = [ ];
        -    $object->[ITEMS] = [ ];
        -
        -    bless $object, $package;
        -    return $object;
        -    };
        -
        -
        -#
        -#   Function: AddItem
        -#
        -#   Adds an item to this file.  Returns whether this added a new item.
        -#
        -sub AddItem #(ExtensionID extension, string itemString) => bool
        -    {
        -    my ($self, $extension, $itemString) = @_;
        -
        -    if (!defined $self->[ITEMS]->[$extension])
        -        {
        -        $self->[ITEMS]->[$extension] = { $itemString => 1 };
        -        return 1;
        -        }
        -    elsif (!exists $self->[ITEMS]->[$extension]->{$itemString})
        -        {
        -        $self->[ITEMS]->[$extension]->{$itemString} = 1;
        -        return 1;
        -        }
        -    else
        -        {
        -        return 0;
        -        };
        -    };
        -
        -
        -#
        -#   Function: HasItem
        -#
        -#   Returns whether the item exists in this file.
        -#
        -sub HasItem #(ExtensionID extension, string itemString) => bool
        -    {
        -    my ($self, $extension, $itemString) = @_;
        -
        -    if (defined $self->[ITEMS]->[$extension])
        -        {  return exists $self->[ITEMS]->[$extension]->{$itemString};  }
        -    else
        -        {  return 0;  };
        -    };
        -
        -
        -#
        -#   Function: DeleteItem
        -#
        -#   Deletes the passed item.  Returns whether it existed.
        -#
        -sub DeleteItem #(ExtensionID extension, string itemString) => bool
        -    {
        -    my ($self, $extension, $itemString) = @_;
        -
        -    if (!defined $self->[ITEMS]->[$extension])
        -        {  return 0;  }
        -    elsif (exists $self->[ITEMS]->[$extension]->{$itemString})
        -        {
        -        delete $self->[ITEMS]->[$extension]->{$itemString};
        -        return 1;
        -        }
        -    else
        -        {  return 0;  };
        -    };
        -
        -
        -#
        -#   Function: ListItems
        -#
        -#   Returns an array of all the item strings defined for a particular extension, or an empty list if none.
        -#
        -sub ListItems #(ExtensionID extension) => string array
        -    {
        -    my ($self, $extension) = @_;
        -
        -    if (defined $self->[ITEMS]->[$extension])
        -        {  return keys %{$self->[ITEMS]->[$extension]};  }
        -    else
        -        {  return ( );  };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/Item.pm b/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/Item.pm
        deleted file mode 100644
        index b43475697..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/Item.pm
        +++ /dev/null
        @@ -1,202 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::SourceDB::Item
        -#
        -###############################################################################
        -#
        -#   A base class for something being tracked in <NaturalDocs::SourceDB>.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -
        -package NaturalDocs::SourceDB::Item;
        -
        -use NaturalDocs::DefineMembers 'DEFINITIONS';
        -
        -
        -#
        -#   Variables: Members
        -#
        -#   The following constants are indexes into the object array.
        -#
        -#   DEFINITIONS - A hashref that maps <FileNames> to either <NaturalDocs::SourceDB::ItemDefinition>-derived objects or
        -#                         serves as an existence hashref depending on whether the extension only tracks existence.  Will be undef if
        -#                         there are none.
        -#
        -
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -sub New
        -    {
        -    my $class = shift;
        -
        -    my $object = [ ];
        -    bless $object, $class;
        -
        -    return $object;
        -    };
        -
        -
        -
        -###############################################################################
        -#
        -#   Group: Definition Functions
        -#
        -#   These functions should be called by <NaturalDocs::SourceDB>.  You should not be calling them directly.  Call functions
        -#   like <NaturalDocs::SourceDB->AddDefinition()> instead.
        -#
        -
        -
        -#
        -#   Function: AddDefinition
        -#
        -#   Adds a definition for the passed <FileName>.  If it's already defined, the new definition will be ignored.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName>.
        -#       definition - The definition, which must be an object derived from <NaturalDocs::SourceDB::ItemDefinition> or undef if
        -#                       the extension only tracks existence.
        -#
        -#   Returns:
        -#
        -#       Whether the definition was added, which is to say, whether this was the first definition for the passed <FileName>.
        -#
        -sub AddDefinition #(FileName file, optional NaturalDocs::SourceDB::ItemDefinition definition) => bool
        -    {
        -    my ($self, $file, $definition) = @_;
        -
        -    if (!defined $self->[DEFINITIONS])
        -        {  $self->[DEFINITIONS] = { };  };
        -
        -    if (!exists $self->[DEFINITIONS]->{$file})
        -        {
        -        if (!defined $definition)
        -            {  $definition = 1;  };
        -
        -        $self->[DEFINITIONS]->{$file} = $definition;
        -        return 1;
        -        }
        -    else
        -        {  return 0;  };
        -    };
        -
        -
        -#
        -#   Function: ChangeDefinition
        -#
        -#   Changes the definition for the passed <FileName>.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName>.
        -#       definition - The definition, which must be an object derived from <NaturalDocs::SourceDB::ItemDefinition>.
        -#
        -sub ChangeDefinition #(FileName file, NaturalDocs::SourceDB::ItemDefinition definition)
        -    {
        -    my ($self, $file, $definition) = @_;
        -
        -    if (!defined $self->[DEFINITIONS] || !exists $self->[DEFINITIONS]->{$file})
        -        {  die "Tried to change a non-existant definition in SourceD::Item.";  };
        -
        -    $self->[DEFINITIONS]->{$file} = $definition;
        -    };
        -
        -
        -#
        -#   Function: GetDefinition
        -#
        -#   Returns the <NaturalDocs::SourceDB::ItemDefinition>-derived object for the passed <FileName>, non-zero if it only tracks
        -#   existence, or undef if there is no definition.
        -#
        -sub GetDefinition #(FileName file) => NaturalDocs::SourceDB::ItemDefinition or bool
        -    {
        -    my ($self, $file) = @_;
        -
        -    if (defined $self->[DEFINITIONS])
        -        {  return $self->[DEFINITIONS]->{$file};  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: DeleteDefinition
        -#
        -#   Removes the definition for the passed <FileName>.  Returns whether it was successful, meaning whether a definition existed
        -#   for that file.
        -#
        -sub DeleteDefinition #(FileName file) => bool
        -    {
        -    my ($self, $file) = @_;
        -
        -    if (defined $self->[DEFINITIONS])
        -        {
        -        if (exists $self->[DEFINITIONS]->{$file})
        -            {
        -            delete $self->[DEFINITIONS]->{$file};
        -
        -            if (!scalar keys %{$self->[DEFINITIONS]})
        -                {  $self->[DEFINITIONS] = undef;  };
        -
        -            return 1;
        -            };
        -        };
        -
        -    return 0;
        -    };
        -
        -
        -#
        -#   Function: HasDefinitions
        -#
        -#   Returns whether there are any definitions for this item.
        -#
        -sub HasDefinitions # => bool
        -    {
        -    my $self = shift;
        -    return (defined $self->[DEFINITIONS]);
        -    };
        -
        -
        -#
        -#   Function: HasDefinition
        -#
        -#   Returns whether there is a definition for the passed <FileName>.
        -#
        -sub HasDefinition #(FileName file) => bool
        -    {
        -    my ($self, $file) = @_;
        -
        -    if (defined $self->[DEFINITIONS])
        -        {  return (exists $self->[DEFINITIONS]->{$file});  }
        -    else
        -        {  return 0;  };
        -    };
        -
        -
        -#
        -#   Function: GetAllDefinitionsHashRef
        -#
        -#   Returns a hashref of all the definitions of this item.  *Do not change.*  The keys are the <FileNames>, and the values are
        -#   either <NaturalDocs::SourceDB::ItemDefinition>-derived objects or it's just an existence hashref if those aren't used.
        -#
        -sub GetAllDefinitionsHashRef
        -    {
        -    my $self = shift;
        -    return $self->[DEFINITIONS];
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/ItemDefinition.pm b/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/ItemDefinition.pm
        deleted file mode 100644
        index 5fe82f839..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/ItemDefinition.pm
        +++ /dev/null
        @@ -1,46 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::SourceDB::ItemDefinition
        -#
        -###############################################################################
        -#
        -#   A base class for all item definitions for extensions that track more than existence.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -
        -package NaturalDocs::SourceDB::ItemDefinition;
        -
        -
        -#
        -#   Function: Compare
        -#
        -#   Returns whether the definitions are equal.  This version returns true by default, you must override it in your subclasses
        -#   to make the results relevant.  This is important for <NaturalDocs::SourceDB->AnalyzeTrackedFileChanges()>.
        -#
        -#   This will only be called between objects of the same <ExtensionID>.  If you use multiple derived classes for the same
        -#   <ExtensionID>, you will have to take that into account yourself.
        -#
        -#   Parameters:
        -#
        -#       other - Another <NaturalDocs::SourceDB::ItemDefinition>-derived object to compare this one to.  It will always be from
        -#                  the same <ExtensionID>.
        -#
        -#   Returns:
        -#
        -#       Whether they are equal.
        -#
        -sub Compare #(other)
        -    {
        -    return 1;
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/WatchedFileDefinitions.pm b/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/WatchedFileDefinitions.pm
        deleted file mode 100644
        index f42bbab38..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/SourceDB/WatchedFileDefinitions.pm
        +++ /dev/null
        @@ -1,160 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::SourceDB::WatchedFileDefinitions
        -#
        -###############################################################################
        -#
        -#   A class to track the definitions appearing in a watched file.  This is only used for extensions that track definition info with
        -#   <NaturalDocs::SourceDB::ItemDefinition>-derived objects.  Do not use it for extensions that only track existence.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -
        -package NaturalDocs::SourceDB::WatchedFileDefinitions;
        -
        -
        -#
        -#   Variables: Members
        -#
        -#   This object would only have one member, which is an array, so the object itself serves as that member.
        -#
        -#   <ExtensionIDs> are used as indexes into this object.  Each entry is a hashref that maps item strings to
        -#   <NaturalDocs::SourceDB::ItemDefinition>-derived objects.  This is only done for extensions that use those objects to track
        -#   definitions, it's not needed for extensions that only track existence.  If there are no definitions, the entry will be undef.
        -#
        -
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -sub New
        -    {
        -    my $class = shift;
        -
        -    my $object = [ ];
        -    bless $object, $class;
        -
        -    return $object;
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Definition Functions
        -#
        -
        -
        -#
        -#   Function: AddDefinition
        -#
        -#   Adds a definition for the passed item string.  If it's already defined, the new definition will be ignored.
        -#
        -#   Parameters:
        -#
        -#       extension - The <ExtensionID>.
        -#       itemString - The item string.
        -#       definition - The definition, which must be an object derived from <NaturalDocs::SourceDB::ItemDefinition>.
        -#
        -#   Returns:
        -#
        -#       Whether the definition was added, which is to say, whether this was the first definition for the passed <FileName>.
        -#
        -sub AddDefinition #(ExtensionID extension, string itemString, NaturalDocs::SourceDB::ItemDefinition definition) => bool
        -    {
        -    my ($self, $extension, $itemString, $definition) = @_;
        -
        -    if (!defined $self->[$extension])
        -        {  $self->[$extension] = { };  };
        -
        -    if (!exists $self->[$extension]->{$itemString})
        -        {
        -        $self->[$extension]->{$itemString} = $definition;
        -        return 1;
        -        }
        -    else
        -        {  return 0;  };
        -    };
        -
        -
        -#
        -#   Function: GetDefinition
        -#
        -#   Returns the <NaturalDocs::SourceDB::ItemDefinition>-derived object for the passed item string  or undef if there is none.
        -#
        -sub GetDefinition #(ExtensionID extension, string itemString) => NaturalDocs::SourceDB::ItemDefinition
        -    {
        -    my ($self, $extension, $itemString) = @_;
        -
        -    if (defined $self->[$extension])
        -        {  return $self->[$extension]->{$itemString};  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: DeleteDefinition
        -#
        -#   Removes the definition for the passed item string.  Returns whether it was successful, meaning whether a definition existed
        -#   for that item.
        -#
        -sub DeleteDefinition #(ExtensionID extension, string itemString) => bool
        -    {
        -    my ($self, $extension, $itemString) = @_;
        -
        -    if (defined $self->[$extension])
        -        {
        -        if (exists $self->[$extension]->{$itemString})
        -            {
        -            delete $self->[$extension]->{$itemString};
        -
        -            if (!scalar keys %{$self->[$extension]})
        -                {  $self->[$extension] = undef;  };
        -
        -            return 1;
        -            };
        -        };
        -
        -    return 0;
        -    };
        -
        -
        -#
        -#   Function: HasDefinitions
        -#
        -#   Returns whether there are any definitions for this item.
        -#
        -sub HasDefinitions #(ExtensionID extension) => bool
        -    {
        -    my ($self, $extension) = @_;
        -
        -    return (defined $self->[$extension]);
        -    };
        -
        -
        -#
        -#   Function: HasDefinition
        -#
        -#   Returns whether there is a definition for the passed item string.
        -#
        -sub HasDefinition #(ExtensionID extension, string itemString) => bool
        -    {
        -    my ($self, $extension, $itemString) = @_;
        -
        -    if (defined $self->[$extension])
        -        {  return (exists $self->[$extension]->{$itemString});  }
        -    else
        -        {  return 0;  };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/StatusMessage.pm b/vendor/naturaldocs/Modules/NaturalDocs/StatusMessage.pm
        deleted file mode 100644
        index e374c0e55..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/StatusMessage.pm
        +++ /dev/null
        @@ -1,103 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::StatusMessage
        -#
        -###############################################################################
        -#
        -#   A package to handle status message updates.  Automatically handles <NaturalDocs::Settings->IsQuiet()>.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::StatusMessage;
        -
        -
        -#
        -#   var: message
        -#   The message to display.
        -#
        -my $message;
        -
        -#
        -#   var: total
        -#   The number of items to work through.
        -#
        -my $total;
        -
        -#
        -#   var: completed
        -#   The number of items completed.
        -#
        -my $completed;
        -
        -#
        -#   var: lastMessageTime
        -#   The time the last message was posted.
        -#
        -my $lastMessageTime;
        -
        -
        -#
        -#   constant: TIME_BETWEEN_UPDATES
        -#   The number of seconds that should occur between updates.
        -#
        -use constant TIME_BETWEEN_UPDATES => 10;
        -
        -
        -
        -#
        -#   Function: Start
        -#
        -#   Starts the status message.
        -#
        -#   Parameters:
        -#
        -#       message - The message to post.
        -#       total - The number of items that are going to be worked through.
        -#
        -sub Start #(message, total)
        -    {
        -    my $self = shift;
        -
        -    if (!NaturalDocs::Settings->IsQuiet())
        -        {
        -        ($message, $total) = @_;
        -        $completed = 0;
        -
        -        print $message . "\n";
        -
        -        $lastMessageTime = time();
        -        };
        -    };
        -
        -
        -#
        -#   Function: CompletedItem
        -#
        -#   Should be called every time an item is completed.
        -#
        -sub CompletedItem
        -    {
        -    my $self = shift;
        -
        -    if (!NaturalDocs::Settings->IsQuiet())
        -        {
        -        # We scale completed by 100 since we need to anyway to get the percentage.
        -
        -        $completed += 100;
        -
        -        if (time() >= $lastMessageTime + TIME_BETWEEN_UPDATES && $completed != $total * 100)
        -            {
        -            print $message . ' (' . ($completed / $total) . '%)' . "\n";
        -            $lastMessageTime = time();
        -            };
        -        };
        -    };
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/SymbolString.pm b/vendor/naturaldocs/Modules/NaturalDocs/SymbolString.pm
        deleted file mode 100644
        index facebb289..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/SymbolString.pm
        +++ /dev/null
        @@ -1,213 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::SymbolString
        -#
        -###############################################################################
        -#
        -#   A package to manage <SymbolString> handling throughout the program.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::SymbolString;
        -
        -
        -#
        -#   Function: FromText
        -#
        -#   Extracts and returns a <SymbolString> from plain text.
        -#
        -#   This should be the only way to get a <SymbolString> from plain text, as the splitting and normalization must be consistent
        -#   throughout the application.
        -#
        -sub FromText #(string textSymbol)
        -    {
        -    my ($self, $textSymbol) = @_;
        -
        -    # The internal format of a symbol is all the normalized identifiers separated by 0x1F characters.
        -
        -    # Convert whitespace and reserved characters to spaces, and condense multiple consecutive ones.
        -    $textSymbol =~ tr/ \t\r\n\x1C\x1D\x1E\x1F/ /s;
        -
        -    # DEPENDENCY: ReferenceString->MakeFrom() assumes all 0x1E characters were removed.
        -    # DEPENDENCY: ReferenceString->MakeFrom() assumes this encoding doesn't use 0x1E characters.
        -
        -    # Remove spaces unless they're separating two alphanumeric/underscore characters.
        -    $textSymbol =~ s/^ //;
        -    $textSymbol =~ s/ $//;
        -    $textSymbol =~ s/(\W) /$1/g;
        -    $textSymbol =~ s/ (\W)/$1/g;
        -
        -    # Remove trailing empty parenthesis, so Function and Function() are equivalent.
        -    $textSymbol =~ s/\(\)$//;
        -
        -    # Split the string into pieces.
        -    my @pieces = split(/(\.|::|->)/, $textSymbol);
        -    my $symbolString;
        -
        -    my $lastWasSeparator = 1;
        -
        -    foreach my $piece (@pieces)
        -        {
        -        if ($piece =~ /^(?:\.|::|->)$/)
        -            {
        -            if (!$lastWasSeparator)
        -                {
        -                $symbolString .= "\x1F";
        -                $lastWasSeparator = 1;
        -                };
        -            }
        -        elsif (length $piece)
        -            {
        -            $symbolString .= $piece;
        -            $lastWasSeparator = 0;
        -            };
        -        # Ignore empty pieces
        -        };
        -
        -    $symbolString =~ s/\x1F$//;
        -
        -    return $symbolString;
        -    };
        -
        -
        -#
        -#   Function: ToText
        -#
        -#   Converts a <SymbolString> to text, using the passed separator.
        -#
        -sub ToText #(SymbolString symbolString, string separator)
        -    {
        -    my ($self, $symbolString, $separator) = @_;
        -
        -    my @identifiers = $self->IdentifiersOf($symbolString);
        -    return join($separator, @identifiers);
        -    };
        -
        -
        -#
        -#   Function: ToBinaryFile
        -#
        -#   Writes a <SymbolString> to the passed filehandle.  Can also encode an undef.
        -#
        -#   Parameters:
        -#
        -#       fileHandle - The filehandle to write to.
        -#       symbol - The <SymbolString> to write, or undef.
        -#
        -#   Format:
        -#
        -#       > [UInt8: number of identifiers]
        -#       >    [AString16: identifier] [AString16: identifier] ...
        -#
        -#       Undef is represented by a zero for the number of identifiers.
        -#
        -sub ToBinaryFile #(FileHandle fileHandle, SymbolString symbol)
        -    {
        -    my ($self, $fileHandle, $symbol) = @_;
        -
        -    my @identifiers;
        -    if (defined $symbol)
        -        {  @identifiers = $self->IdentifiersOf($symbol);  };
        -
        -    print $fileHandle pack('C', scalar @identifiers);
        -
        -    foreach my $identifier (@identifiers)
        -        {
        -        print $fileHandle pack('nA*', length($identifier), $identifier);
        -        };
        -    };
        -
        -
        -#
        -#   Function: FromBinaryFile
        -#
        -#   Loads a <SymbolString> or undef from the filehandle and returns it.
        -#
        -#   Parameters:
        -#
        -#       fileHandle - The filehandle to read from.
        -#
        -#   Returns:
        -#
        -#       The <SymbolString> or undef.
        -#
        -#   See also:
        -#
        -#       See <ToBinaryFile()> for format and dependencies.
        -#
        -sub FromBinaryFile #(FileHandle fileHandle)
        -    {
        -    my ($self, $fileHandle) = @_;
        -
        -    my $raw;
        -
        -    # [UInt8: number of identifiers or 0 if none]
        -
        -    read($fileHandle, $raw, 1);
        -    my $identifierCount = unpack('C', $raw);
        -
        -    my @identifiers;
        -
        -    while ($identifierCount)
        -        {
        -        # [AString16: identifier] [AString16: identifier] ...
        -
        -        read($fileHandle, $raw, 2);
        -        my $identifierLength = unpack('n', $raw);
        -
        -        my $identifier;
        -        read($fileHandle, $identifier, $identifierLength);
        -
        -        push @identifiers, $identifier;
        -
        -        $identifierCount--;
        -        };
        -
        -    if (scalar @identifiers)
        -        {  return $self->Join(@identifiers);  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: IdentifiersOf
        -#
        -#   Returns the <SymbolString> as an array of identifiers.
        -#
        -sub IdentifiersOf #(SymbolString symbol)
        -    {
        -    my ($self, $symbol) = @_;
        -    return split(/\x1F/, $symbol);
        -    };
        -
        -
        -#
        -#   Function: Join
        -#
        -#   Takes a list of identifiers and/or <SymbolStrings> and returns it as a new <SymbolString>.
        -#
        -sub Join #(string/SymbolString identifier/symbol, string/SymolString identifier/symbol, ...)
        -    {
        -    my ($self, @pieces) = @_;
        -
        -    # Can't have undefs screwing everything up.
        -    while (scalar @pieces && !defined $pieces[0])
        -        {  shift @pieces;  };
        -
        -    # We need to test @pieces first because joining on an empty array returns an empty string rather than undef.
        -    if (scalar @pieces)
        -       {  return join("\x1F", @pieces);  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable.pm b/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable.pm
        deleted file mode 100644
        index cf868bd6f..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable.pm
        +++ /dev/null
        @@ -1,1985 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::SymbolTable
        -#
        -###############################################################################
        -#
        -#   A package that handles all the gory details of managing symbols.  It handles where they are defined, which files
        -#   reference them, if any are undefined or duplicated, and loading and saving them to a file.
        -#
        -#   Usage and Dependencies:
        -#
        -#       - At any time, <RebuildAllIndexes()> can be called.
        -#
        -#       - <NaturalDocs::Settings>, <NaturalDocs::Languages>, and <NaturalDocs::Project> must be initialized before use.
        -#
        -#       - <Load()> must be called to initialize the package.  At this point, the <Information Functions> will return the symbol
        -#         table as of the last time Natural Docs was run.
        -#
        -#       - Note that <Load()> and <Save()> only manage <REFERENCE_TEXT> references.  All other reference types must be
        -#         managed by their respective classes.  They should be readded after <Load()> to recreate the state of the last time
        -#         Natural Docs was run.
        -#
        -#       - <Purge()> must be called, and then <NaturalDocs::Parser->ParseForInformation()> on all files that have changed so it
        -#         can fully resolve the symbol table via the <Modification Functions>.  Afterwards <PurgeResolvingInfo()> can be called
        -#         to reclaim some memory, and the symbol table will reflect the current state of the code.
        -#
        -#       - <Save()> must be called to commit any changes to the symbol table back to disk.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -
        -use NaturalDocs::SymbolTable::Symbol;
        -use NaturalDocs::SymbolTable::SymbolDefinition;
        -use NaturalDocs::SymbolTable::Reference;
        -use NaturalDocs::SymbolTable::File;
        -use NaturalDocs::SymbolTable::ReferenceTarget;
        -use NaturalDocs::SymbolTable::IndexElement;
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::SymbolTable;
        -
        -
        -
        -###############################################################################
        -# Group: Variables
        -
        -#
        -#   handle: SYMBOLTABLE_FILEHANDLE
        -#
        -#   The file handle used with <SymbolTable.nd>.
        -#
        -
        -#
        -#   hash: symbols
        -#
        -#   A hash of all <SymbolStrings>.  The keys are the <SymbolStrings> and the values are <NaturalDocs::SymbolTable::Symbol>
        -#   objects.
        -#
        -#   Prior to <PurgeResolvingInfo()>, both defined symbols and symbols that are merely potential interpretations of references
        -#   will be here.  Afterwards, only defined symbols will be here.
        -#
        -my %symbols;
        -
        -#
        -#   hash: references
        -#
        -#   A hash of all references in the project.  The keys are <ReferenceStrings> and the values are
        -#   <NaturalDocs::SymbolTable::Reference> objects.
        -#
        -#   Prior to <PurgeResolvingInfo()>, all possible interpretations will be stored for each reference.  Afterwards, only the current
        -#   interpretation will be.
        -#
        -my %references;
        -
        -#
        -#   hash: files
        -#
        -#   A hash of all the files that define symbols and references in the project.  The keys are the <FileNames>, and the values are
        -#   <NaturalDocs::SymbolTable::File> objects.
        -#
        -#   After <PurgeResolvingInfo()>, this hash will be empty.
        -#
        -my %files;
        -
        -#
        -#   object: watchedFile
        -#
        -#   A <NaturalDocs::SymbolTable::File> object of the file being watched for changes.  This is compared to the version in <files>
        -#   to see if anything was changed since the last parse.
        -#
        -my $watchedFile;
        -
        -#
        -#   string: watchedFileName
        -#
        -#   The <FileName> of the watched file, if any.  If there is no watched file, this will be undef.
        -#
        -my $watchedFileName;
        -
        -#
        -#   hash: watchedFileSymbolDefinitions
        -#
        -#   A hashref of the symbol definition information for all the <SymbolStrings> in the watched file.  The keys are the symbol strings,
        -#   and the values are <NaturalDocs::SymbolTable::SymbolDefinition> objects.
        -#
        -my %watchedFileSymbolDefinitions;
        -
        -
        -#
        -#   hash: indexes
        -#
        -#   A hash of generated symbol indexes.  The keys are <TopicTypes> and the values are sorted arrayrefs of
        -#   <NaturalDocs::SymbolTable::IndexElements>, or undef if its empty.
        -#
        -my %indexes;
        -
        -
        -#
        -#   hash: indexChanges
        -#
        -#   A hash of all the indexes that have changed.  The keys are the <TopicTypes> and the entries are undef if they have not
        -#   changed, or 1 if they have.  The key will not exist if the <TopicType> has not been checked.
        -#
        -my %indexChanges;
        -
        -
        -#
        -#   hash: indexSectionsWithContent
        -#
        -#   A hash of which sections in an index have content.  The keys are the <TopicTypes> of each index, and the values are
        -#   arrayrefs of bools where the first represents symbols, the second numbers, and the rest A-Z.  If there is no information
        -#   available for an index, it's entry will not exist here.
        -#
        -my %indexSectionsWithContent;
        -
        -
        -#
        -#   bool: rebuildIndexes
        -#
        -#   Whether all indexes should be rebuilt regardless of whether they have been changed.
        -#
        -my $rebuildIndexes;
        -
        -
        -
        -###############################################################################
        -# Group: Files
        -
        -
        -#
        -#   File: SymbolTable.nd
        -#
        -#   The storage file for the symbol table.
        -#
        -#   Format:
        -#
        -#       > [BINARY_FORMAT]
        -#       > [VersionInt: app version]
        -#
        -#       The file starts with the standard <BINARY_FORMAT> <VersionInt> header.
        -#
        -#       The first stage of the file is for symbol definitions, analogous to <symbols>.
        -#
        -#       > [SymbolString: symbol or undef to end] ...
        -#       >
        -#       > [UInt16: number of definitions]
        -#       >
        -#       >    [AString16: global definition file] [AString16: TopicType]
        -#       >       [AString16: prototype] [AString16: summary]
        -#       >
        -#       >    [AString16: definition file] ...
        -#       >
        -#       >    ...
        -#
        -#       These blocks continue until the <SymbolString> is undef.  Only defined symbols will be included in this file, so
        -#       number of definitions will never be zero.  The first one is always the global definition.  If a symbol does not have a
        -#       prototype or summary, the UInt16 length of the string will be zero.
        -#
        -#       The second stage is for references, which is analogous to <references>.  Only <REFERENCE_TEXT> references are
        -#       stored in this file, and their <Resolving Flags> are implied so they aren't stored either.
        -#
        -#       > [ReferenceString (no type, resolving flags): reference or undef to end]
        -#       >
        -#       > [UInt8: number of definition files]
        -#       >    [AString16: definition file] [AString16: definition file] ...
        -#
        -#       These blocks continue until the <ReferenceString> is undef.  Since there can be multiple using <SymbolStrings>, those
        -#       continue until the number of identifiers is zero.  Note that all interpretations are rebuilt rather than stored.
        -#
        -#   See Also:
        -#
        -#       <File Format Conventions>
        -#
        -#   Revisions:
        -#
        -#       1.3:
        -#
        -#           - Symbol <TopicTypes> were changed from UInt8s to AString16s, now that <TopicTypes> are strings instead of
        -#             integer constants.
        -#
        -#       1.22:
        -#
        -#           - File format was completely rebuilt to accommodate the new symbol format and to be in binary.  To see the plain text
        -#             format prior to 1.22, check out 1.21's version of this file from CVS.  It is too big a change to note here.
        -#
        -
        -
        -#
        -#   File: IndexInfo.nd
        -#
        -#   The storage file for information about the indexes.
        -#
        -#   Format:
        -#
        -#       > [Standard Header]
        -#
        -#       The standard binary file header.
        -#
        -#       > [AString16: index topic name]
        -#       > [uint8: symbols have content (0 or 1)]
        -#       > [uint8: numbers have content (0 or 1)]
        -#       > [uint8: A has content] [uint8: B has content] ...
        -#       > ...
        -#
        -#       Every index that has information about it is stored with the topic type name first, then 28 uint8s that say whether that
        -#       part of the index has content or not.  The first is for symbols, the second is for numbers, and the rest are for A-Z.  If an
        -#       index's state is unknown, it won't appear in this file.
        -#
        -#   Revisions:
        -#
        -#       1.4:
        -#
        -#           - The file is introduced.
        -#
        -
        -
        -
        -###############################################################################
        -# Group: File Functions
        -
        -
        -#
        -#   Function: Load
        -#
        -#   Loads all data files from disk.
        -#
        -sub Load
        -    {
        -    my ($self) = @_;
        -
        -    $self->LoadSymbolTable();
        -    $self->LoadIndexInfo();
        -    };
        -
        -
        -#
        -#   Function: LoadSymbolTable
        -#
        -#   Loads <SymbolTable.nd> from disk.
        -#
        -sub LoadSymbolTable
        -    {
        -    my ($self) = @_;
        -
        -    my $fileIsOkay;
        -
        -    if (!NaturalDocs::Settings->RebuildData() &&
        -        open(SYMBOLTABLE_FILEHANDLE, '<' . NaturalDocs::Project->DataFile('SymbolTable.nd')) )
        -        {
        -        # See if it's binary.
        -        binmode(SYMBOLTABLE_FILEHANDLE);
        -
        -        my $firstChar;
        -        read(SYMBOLTABLE_FILEHANDLE, $firstChar, 1);
        -
        -        if ($firstChar == ::BINARY_FORMAT())
        -            {
        -            my $version = NaturalDocs::Version->FromBinaryFile(\*SYMBOLTABLE_FILEHANDLE);
        -
        -            # 1.3 is incompatible with previous versions.
        -
        -            if (NaturalDocs::Version->CheckFileFormat( $version, NaturalDocs::Version->FromString('1.3') ))
        -                {  $fileIsOkay = 1;  }
        -            else
        -                {  close(SYMBOLTABLE_FILEHANDLE);  };
        -            }
        -
        -        else
        -            {  close(SYMBOLTABLE_FILEHANDLE);  };
        -        };
        -
        -
        -    if (!$fileIsOkay)
        -        {
        -        NaturalDocs::Project->ReparseEverything();
        -        return;
        -        }
        -
        -    my $raw;
        -
        -
        -    # Symbols
        -
        -    for (;;)
        -        {
        -        # [SymbolString: symbol or undef to end]
        -
        -        my $symbol = NaturalDocs::SymbolString->FromBinaryFile(\*SYMBOLTABLE_FILEHANDLE);
        -
        -        if (!defined $symbol)
        -            {  last;  };
        -
        -        my $symbolObject = NaturalDocs::SymbolTable::Symbol->New();
        -        $symbols{$symbol} = $symbolObject;
        -
        -        # [UInt16: number of definitions]
        -
        -        read(SYMBOLTABLE_FILEHANDLE, $raw, 2);
        -        my $definitionCount = unpack('n', $raw);
        -
        -        do
        -            {
        -            # [AString16: (global?) definition file]
        -
        -            read(SYMBOLTABLE_FILEHANDLE, $raw, 2);
        -            my $fileLength = unpack('n', $raw);
        -
        -            my $file;
        -            read(SYMBOLTABLE_FILEHANDLE, $file, $fileLength);
        -
        -            # [AString16: TopicType]
        -
        -            read(SYMBOLTABLE_FILEHANDLE, $raw, 2);
        -            my $typeLength = unpack('n', $raw);
        -
        -            my $type;
        -            read(SYMBOLTABLE_FILEHANDLE, $type, $typeLength);
        -
        -            # [AString16: prototype]
        -
        -            read(SYMBOLTABLE_FILEHANDLE, $raw, 2);
        -            my $prototypeLength = unpack('n', $raw);
        -
        -            my $prototype;
        -            if ($prototypeLength)
        -                {  read(SYMBOLTABLE_FILEHANDLE, $prototype, $prototypeLength);  };
        -
        -            # [AString16: summary]
        -
        -            read(SYMBOLTABLE_FILEHANDLE, $raw, 2);
        -            my $summaryLength = unpack('n', $raw);
        -
        -            my $summary;
        -            if ($summaryLength)
        -                {  read(SYMBOLTABLE_FILEHANDLE, $summary, $summaryLength);  };
        -
        -            $symbolObject->AddDefinition($file, $type, $prototype, $summary);
        -
        -            # Add it.
        -
        -            if (!exists $files{$file})
        -                {  $files{$file} = NaturalDocs::SymbolTable::File->New();  };
        -
        -            $files{$file}->AddSymbol($symbol);
        -
        -            $definitionCount--;
        -            }
        -        while ($definitionCount);
        -        };
        -
        -
        -    # References
        -
        -    for (;;)
        -        {
        -        # [ReferenceString (no type, resolving flags): reference or undef to end]
        -
        -        my $referenceString = NaturalDocs::ReferenceString->FromBinaryFile(\*SYMBOLTABLE_FILEHANDLE,
        -                                                                                                              ::BINARYREF_NOTYPE() |
        -                                                                                                              ::BINARYREF_NORESOLVINGFLAGS(),
        -                                                                                                              ::REFERENCE_TEXT(), undef);
        -
        -        if (!defined $referenceString)
        -            {  last;  };
        -
        -        my $referenceObject = NaturalDocs::SymbolTable::Reference->New();
        -        $references{$referenceString} = $referenceObject;
        -
        -        # [UInt8: number of definition files]
        -
        -        read(SYMBOLTABLE_FILEHANDLE, $raw, 1);
        -        my $definitionCount = unpack('C', $raw);
        -        do
        -            {
        -            # [AString16: definition file] [AString16: definition file] ...
        -
        -            read(SYMBOLTABLE_FILEHANDLE, $raw, 2);
        -            my $definitionLength = unpack('n', $raw);
        -
        -            my $definition;
        -            read(SYMBOLTABLE_FILEHANDLE, $definition, $definitionLength);
        -
        -            # Add it.
        -
        -            $referenceObject->AddDefinition($definition);
        -
        -            if (!exists $files{$definition})
        -                {  $files{$definition} = NaturalDocs::SymbolTable::File->New();  };
        -
        -            $files{$definition}->AddReference($referenceString);
        -
        -            $definitionCount--;
        -            }
        -        while ($definitionCount);
        -
        -        $self->GenerateInterpretations($referenceString);
        -        $self->InterpretReference($referenceString);
        -        };
        -
        -    close(SYMBOLTABLE_FILEHANDLE);
        -    };
        -
        -
        -#
        -#   Function: LoadIndexInfo
        -#
        -#   Loads <IndexInfo.nd> from disk.
        -#
        -sub LoadIndexInfo
        -    {
        -    my ($self) = @_;
        -
        -    if (NaturalDocs::Settings->RebuildData())
        -        {  return;  };
        -
        -    my $version = NaturalDocs::BinaryFile->OpenForReading( NaturalDocs::Project->DataFile('IndexInfo.nd') );
        -
        -    if (!defined $version)
        -        {  return;  }
        -
        -    # The file format hasn't changed since it was introduced.
        -    if (!NaturalDocs::Version->CheckFileFormat($version))
        -        {
        -        NaturalDocs::BinaryFile->Close();
        -        return;
        -        };
        -
        -    my $topicTypeName;
        -    while ($topicTypeName = NaturalDocs::BinaryFile->GetAString16())
        -        {
        -        my $topicType = NaturalDocs::Topics->TypeFromName($topicTypeName);
        -        my $content = [ ];
        -
        -        for (my $i = 0; $i < 28; $i++)
        -            {  push @$content, NaturalDocs::BinaryFile->GetUInt8();  };
        -
        -        if (defined $topicType)  # The name in the file could be from a type that was deleted
        -            {  $indexSectionsWithContent{$topicType} = $content;  };
        -        };
        -
        -    NaturalDocs::BinaryFile->Close();
        -    };
        -
        -
        -#
        -#   Function: Purge
        -#
        -#   Purges the symbol table of all symbols and references from files that no longer have Natural Docs content.
        -#
        -sub Purge
        -    {
        -    my ($self) = @_;
        -
        -    my $filesToPurge = NaturalDocs::Project->FilesToPurge();
        -
        -    # We do this in two stages.  First we delete all the references, and then we delete all the definitions.  This causes us to go
        -    # through the list twice, but it makes sure no purged files get added to the build list.  For example, if we deleted all of
        -    # Purge File A's references and definitions, and Purge File B had a reference to one of those symbols, Purge File B
        -    # would be added to the build list because one of its references changed.  By removing all the references in all the files
        -    # before removing the definitions, we avoid this.
        -
        -    foreach my $file (keys %$filesToPurge)
        -        {
        -        if (exists $files{$file})
        -            {
        -            my @references = $files{$file}->References();
        -            foreach my $reference (@references)
        -                {  $self->DeleteReference($reference, $file);  };
        -            };
        -        };
        -
        -    foreach my $file (keys %$filesToPurge)
        -        {
        -        if (exists $files{$file})
        -            {
        -            my @symbols = $files{$file}->Symbols();
        -            foreach my $symbol (@symbols)
        -                {  $self->DeleteSymbol($symbol, $file);  };
        -
        -            delete $files{$file};
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: Save
        -#
        -#   Saves all data files to disk.
        -#
        -sub Save
        -    {
        -    my ($self) = @_;
        -
        -    $self->SaveSymbolTable();
        -    $self->SaveIndexInfo();
        -    };
        -
        -
        -#
        -#   Function: SaveSymbolTable
        -#
        -#   Saves <SymbolTable.nd> to disk.
        -#
        -sub SaveSymbolTable
        -    {
        -    my ($self) = @_;
        -
        -    open (SYMBOLTABLE_FILEHANDLE, '>' . NaturalDocs::Project->DataFile('SymbolTable.nd'))
        -        or die "Couldn't save " . NaturalDocs::Project->DataFile('SymbolTable.nd') . ".\n";
        -
        -    binmode(SYMBOLTABLE_FILEHANDLE);
        -
        -    print SYMBOLTABLE_FILEHANDLE '' . ::BINARY_FORMAT();
        -
        -    NaturalDocs::Version->ToBinaryFile(\*SYMBOLTABLE_FILEHANDLE, NaturalDocs::Settings->AppVersion());
        -
        -
        -    # Symbols
        -
        -    while (my ($symbol, $symbolObject) = each %symbols)
        -        {
        -        # Only existing symbols.
        -        if ($symbolObject->IsDefined())
        -            {
        -            # [SymbolString: symbol or undef to end]
        -
        -            NaturalDocs::SymbolString->ToBinaryFile(\*SYMBOLTABLE_FILEHANDLE, $symbol);
        -
        -            # [UInt16: number of definitions]
        -
        -            my @definitions = $symbolObject->Definitions();
        -            print SYMBOLTABLE_FILEHANDLE pack('n', scalar @definitions);
        -
        -            # [AString16: global definition file] [AString16: TopicType]
        -
        -            print SYMBOLTABLE_FILEHANDLE pack('nA*nA*', length $symbolObject->GlobalDefinition(),
        -                                                                                   $symbolObject->GlobalDefinition(),
        -                                                                                   length $symbolObject->GlobalType(),
        -                                                                                   $symbolObject->GlobalType());
        -
        -            # [AString16: prototype]
        -
        -            my $prototype = $symbolObject->GlobalPrototype();
        -
        -            if (defined $prototype)
        -                {  print SYMBOLTABLE_FILEHANDLE pack('nA*', length($prototype), $prototype);  }
        -            else
        -                {  print SYMBOLTABLE_FILEHANDLE pack('n', 0);  };
        -
        -            # [AString16: summary]
        -
        -            my $summary = $symbolObject->GlobalSummary();
        -
        -            if (defined $summary)
        -                {  print SYMBOLTABLE_FILEHANDLE pack('nA*', length($summary), $summary);  }
        -            else
        -                {  print SYMBOLTABLE_FILEHANDLE pack('n', 0);  };
        -
        -
        -            foreach my $definition (@definitions)
        -                {
        -                if ($definition ne $symbolObject->GlobalDefinition())
        -                    {
        -                    # [AString16: definition file] [AString16: TopicType]
        -
        -                    print SYMBOLTABLE_FILEHANDLE pack('nA*nA*', length $definition, $definition,
        -                                                                                           length $symbolObject->TypeDefinedIn($definition),
        -                                                                                           $symbolObject->TypeDefinedIn($definition));
        -
        -                    # [AString16: prototype]
        -
        -                    my $prototype = $symbolObject->PrototypeDefinedIn($definition);
        -
        -                    if (defined $prototype)
        -                        {  print SYMBOLTABLE_FILEHANDLE pack('nA*', length($prototype), $prototype);  }
        -                    else
        -                        {  print SYMBOLTABLE_FILEHANDLE pack('n', 0);  };
        -
        -                    # [AString16: summary]
        -
        -                    my $summary = $symbolObject->SummaryDefinedIn($definition);
        -
        -                    if (defined $summary)
        -                        {  print SYMBOLTABLE_FILEHANDLE pack('nA*', length($summary), $summary);  }
        -                    else
        -                        {  print SYMBOLTABLE_FILEHANDLE pack('n', 0);  };
        -                    };
        -                };
        -            };
        -        };
        -
        -     # [SymbolString: symbol or undef to end]
        -
        -     NaturalDocs::SymbolString->ToBinaryFile(\*SYMBOLTABLE_FILEHANDLE, undef);
        -
        -
        -     # References
        -
        -    while (my ($reference, $referenceObject) = each %references)
        -        {
        -        my $type = NaturalDocs::ReferenceString->TypeOf($reference);
        -
        -        if ($type == ::REFERENCE_TEXT())
        -            {
        -            # [ReferenceString (no type, resolving flags): reference or undef to end]
        -
        -            NaturalDocs::ReferenceString->ToBinaryFile(\*SYMBOLTABLE_FILEHANDLE, $reference,
        -                                                                             ::BINARYREF_NOTYPE() | ::BINARYREF_NORESOLVINGFLAGS());
        -
        -            # [UInt8: number of definition files]
        -
        -            my @definitions = $referenceObject->Definitions();
        -            print SYMBOLTABLE_FILEHANDLE pack('C', scalar @definitions);
        -
        -            # [AString16: definition file] [AString16: definition file] ...
        -
        -            foreach my $definition (@definitions)
        -                {
        -                print SYMBOLTABLE_FILEHANDLE pack('nA*', length($definition), $definition);
        -                };
        -            };
        -        };
        -
        -    # [ReferenceString (no type, resolving flags): reference or undef to end]
        -
        -    NaturalDocs::ReferenceString->ToBinaryFile(\*SYMBOLTABLE_FILEHANDLE, undef,
        -                                                                     ::BINARYREF_NOTYPE() | ::BINARYREF_NORESOLVINGFLAGS());
        -
        -    close(SYMBOLTABLE_FILEHANDLE);
        -    };
        -
        -
        -#
        -#   Function: SaveIndexInfo
        -#
        -#   Saves <IndexInfo.nd> to disk.
        -#
        -sub SaveIndexInfo
        -    {
        -    my ($self) = @_;
        -
        -    NaturalDocs::BinaryFile->OpenForWriting( NaturalDocs::Project->DataFile('IndexInfo.nd') );
        -
        -    while (my ($topicType, $content) = each %indexSectionsWithContent)
        -        {
        -        NaturalDocs::BinaryFile->WriteAString16( NaturalDocs::Topics->NameOfType($topicType) );
        -
        -        for (my $i = 0; $i < 28; $i++)
        -            {
        -            if ($content->[$i])
        -                {  NaturalDocs::BinaryFile->WriteUInt8(1);  }
        -            else
        -                {  NaturalDocs::BinaryFile->WriteUInt8(0);  };
        -            };
        -        };
        -
        -    NaturalDocs::BinaryFile->Close();
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Modification Functions
        -# These functions should not be called after <PurgeResolvingInfo()>.
        -
        -#
        -#   Function: AddSymbol
        -#
        -#   Adds a symbol definition to the table, if it doesn't already exist.  If the definition changes or otherwise requires the files that
        -#   reference it to be updated, the function will call <NaturalDocs::Project->RebuildFile()> to make sure that they are.
        -#
        -#   Parameters:
        -#
        -#       symbol  - The <SymbolString>.
        -#       file        - The <FileName> where it's defined.
        -#       type      - The symbol's <TopicType>.
        -#       prototype - The symbol's prototype, if applicable.
        -#       summary - The symbol's summary, if applicable.
        -#
        -sub AddSymbol #(symbol, file, type, prototype, summary)
        -    {
        -    my ($self, $symbol, $file, $type, $prototype, $summary) = @_;
        -
        -
        -    # If the symbol doesn't exist...
        -    if (!exists $symbols{$symbol})
        -        {
        -        # Create the symbol.  There are no references that could be interpreted as this or else it would have existed already.
        -
        -        my $newSymbol = NaturalDocs::SymbolTable::Symbol->New();
        -        $newSymbol->AddDefinition($file, $type, $prototype, $summary);
        -
        -        $symbols{$symbol} = $newSymbol;
        -
        -        $self->OnIndexChange($type);
        -        NaturalDocs::Project->RebuildFile($file);
        -        }
        -
        -
        -    # If the symbol already exists...
        -    else
        -        {
        -        my $symbolObject = $symbols{$symbol};
        -
        -        # If the symbol isn't defined, i.e. it was a potential interpretation only...
        -        if (!$symbolObject->IsDefined())
        -            {
        -            $symbolObject->AddDefinition($file, $type, $prototype, $summary);
        -
        -            # See if this symbol provides a better interpretation of any references.  We can assume this symbol has interpretations
        -            # because the object won't exist without either that or definitions.
        -
        -            my %referencesAndScores = $symbolObject->ReferencesAndScores();
        -
        -            while (my ($referenceString, $referenceScore) = each %referencesAndScores)
        -                {
        -                my $referenceObject = $references{$referenceString};
        -
        -                if (!$referenceObject->HasCurrentInterpretation() ||
        -                    $referenceScore > $referenceObject->CurrentScore())
        -                    {
        -                    $referenceObject->SetCurrentInterpretation($symbol);
        -                    $self->OnInterpretationChange($referenceString);
        -                    };
        -                };
        -
        -            $self->OnIndexChange($type);
        -            NaturalDocs::Project->RebuildFile($file);
        -            }
        -
        -        # If the symbol is defined but not in this file...
        -        elsif (!$symbolObject->IsDefinedIn($file))
        -            {
        -            $symbolObject->AddDefinition($file, $type, $prototype, $summary);
        -
        -            $self->OnIndexChange($type);
        -            NaturalDocs::Project->RebuildFile($file);
        -
        -            # We don't have to check other files because if the symbol is defined it already has a global definiton,
        -            # and everything else is either using that or its own definition, and thus wouldn't be affected by this.
        -            };
        -
        -        # If the symbol was already defined in this file, ignore it.
        -
        -        };
        -
        -
        -    # Add it to the file index.
        -
        -    if (!exists $files{$file})
        -        {  $files{$file} = NaturalDocs::SymbolTable::File->New();  };
        -
        -    $files{$file}->AddSymbol($symbol);
        -
        -
        -    # Add it to the watched file, if necessary.
        -
        -    if (defined $watchedFileName)
        -        {
        -        $watchedFile->AddSymbol($symbol);
        -
        -        if (!exists $watchedFileSymbolDefinitions{$symbol})
        -            {
        -            $watchedFileSymbolDefinitions{$symbol} =
        -                 NaturalDocs::SymbolTable::SymbolDefinition->New($type, $prototype, $summary);
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: AddReference
        -#
        -#   Adds a reference to the table, if it doesn't already exist.
        -#
        -#   Parameters:
        -#
        -#       type        - The <ReferenceType>.
        -#       symbol    - The reference <SymbolString>.
        -#       scope      - The scope <SymbolString> it appears in.
        -#       using       - An arrayref of scope <SymbolStrings> accessible to the reference via "using" statements, or undef if none.
        -#       file          - The <FileName> where the reference appears.  This is not required unless the type is <REFERENCE_TEXT>.
        -#       resolvingFlags - The <Resolving Flags> of the reference.  They will be ignored if the type is <REFERENCE_TEXT>.
        -#
        -#   Alternate Parameters:
        -#
        -#       referenceString - The <ReferenceString> to add.
        -#       file - The <FileName> where the reference appears.  This is not required unless the type is <REFERENCE_TEXT>.
        -#
        -sub AddReference #(type, symbol, scope, using, file, resolvingFlags) or (referenceString, file)
        -    {
        -    my ($self, $referenceString, $file);
        -
        -    if (scalar @_ <= 3)
        -        {
        -        ($self, $referenceString, $file) = @_;
        -        }
        -    else
        -        {
        -        my ($type, $symbol, $scope, $using, $resolvingFlags);
        -        ($self, $type, $symbol, $scope, $using, $file, $resolvingFlags) = @_;
        -
        -        $referenceString = NaturalDocs::ReferenceString->MakeFrom($type, $symbol,
        -                                                                                                   NaturalDocs::Languages->LanguageOf($file)->Name(),
        -                                                                                                   $scope, $using, $resolvingFlags);
        -        };
        -
        -
        -    # If the reference doesn't exist...
        -    if (!exists $references{$referenceString})
        -        {
        -        my $referenceObject = NaturalDocs::SymbolTable::Reference->New();
        -
        -        $references{$referenceString} = $referenceObject;
        -
        -        $self->GenerateInterpretations($referenceString);
        -        $self->InterpretReference($referenceString);
        -        }
        -
        -
        -    if (defined $file)
        -        {
        -        $references{$referenceString}->AddDefinition($file);
        -
        -
        -        # Add it to the file index.
        -
        -        if (!exists $files{$file})
        -            {  $files{$file} = NaturalDocs::SymbolTable::File->New();  };
        -
        -        $files{$file}->AddReference($referenceString);
        -
        -
        -        # Add it to the watched file, if necessary.
        -
        -        if (defined $watchedFileName)
        -            {  $watchedFile->AddReference($referenceString);  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: WatchFileForChanges
        -#
        -#   Tracks a file to see if any symbols or references were changed or deleted in ways that would require other files to be rebuilt.
        -#   Assumes that after this function call, the entire file will be parsed again, and thus every symbol and reference will go through
        -#   <AddSymbol()> and <AddReference()>.  Afterwards, call <AnalyzeChanges()> to handle any differences.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName> to watch.
        -#
        -sub WatchFileForChanges #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    $watchedFile = NaturalDocs::SymbolTable::File->New();
        -    $watchedFileName = $file;
        -    %watchedFileSymbolDefinitions = ( );
        -    };
        -
        -
        -#
        -#   Function: AnalyzeChanges
        -#
        -#   Handles any changes found when reparsing a file using <WatchFileForChanges()>.
        -#
        -sub AnalyzeChanges
        -    {
        -    my ($self) = @_;
        -
        -    if (exists $files{$watchedFileName})
        -        {
        -
        -        # Go through the references and remove any that were deleted.  Ones that were added will have already been added to
        -        # the table in AddReference().
        -
        -        my @references = $files{$watchedFileName}->References();
        -        foreach my $reference (@references)
        -            {
        -            if (!$watchedFile->DefinesReference($reference))
        -                {  $self->DeleteReference($reference, $watchedFileName);  };
        -            };
        -        };
        -
        -    # We have to check if the watched file exists again because DeleteReference() could have removed it.  I'm still not sure how a
        -    # file could have references without symbols, but apparently it's happened in the real world because it's crashed on people.
        -    if (exists $files{$watchedFileName})
        -        {
        -        # Go through the symbols.
        -
        -        my $rebuildFile;
        -
        -        my @symbols = $files{$watchedFileName}->Symbols();
        -        foreach my $symbol (@symbols)
        -            {
        -            # Delete symbols that don't exist.
        -
        -            if (!$watchedFile->DefinesSymbol($symbol))
        -                {
        -                $self->DeleteSymbol($symbol, $watchedFileName);
        -                $rebuildFile = 1;
        -                }
        -
        -            else
        -                {
        -                my $symbolObject = $symbols{$symbol};
        -                my $newSymbolDef = $watchedFileSymbolDefinitions{$symbol};
        -
        -                # Update symbols that changed.
        -
        -                if ( $symbolObject->TypeDefinedIn($watchedFileName) ne $newSymbolDef->Type() ||
        -                     $symbolObject->PrototypeDefinedIn($watchedFileName) ne $newSymbolDef->Prototype() ||
        -                     $symbolObject->SummaryDefinedIn($watchedFileName) ne $newSymbolDef->Summary() )
        -                    {
        -                    $self->OnIndexChange($symbolObject->TypeDefinedIn($watchedFileName));
        -                    $self->OnIndexChange($newSymbolDef->Type());
        -                    $rebuildFile = 1;
        -
        -                    $symbolObject->ChangeDefinition($watchedFileName, $newSymbolDef->Type(), $newSymbolDef->Prototype(),
        -                                                                       $newSymbolDef->Summary());
        -
        -                    # If the symbol definition was the global one, we need to update all files that reference it.  If it wasn't, the only file
        -                    # that could references it is itself, and the only way the symbol definition could change in the first place was if it was
        -                    # itself changed.
        -                    if ($symbolObject->GlobalDefinition() eq $watchedFileName)
        -                        {
        -                        # Rebuild the files that have references to this symbol
        -                        my @references = $symbolObject->References();
        -                        foreach my $reference (@references)
        -                            {
        -                            if ($references{$reference}->CurrentInterpretation() eq $symbol)
        -                                {  $self->OnTargetSymbolChange($reference);  };
        -                            }; # While references
        -                        }; # If global definition is watched file
        -                    }; # If the symbol definition changed
        -                }; # If the symbol still exists
        -            }; # foreach symbol in watched file
        -
        -        if ($rebuildFile)
        -            {  NaturalDocs::Project->RebuildFile($watchedFileName);  };
        -
        -        };
        -
        -
        -    $watchedFile = undef;
        -    $watchedFileName = undef;
        -    %watchedFileSymbolDefinitions = ( );
        -    };
        -
        -
        -#
        -#   Function: DeleteReference
        -#
        -#   Deletes a reference from the table.
        -#
        -#   Be careful with this function, as deleting a reference means there are no more of them in the file at all.  The tables do not
        -#   keep track of how many times references appear in a file.  In these cases you should instead call <WatchFileForChanges()>,
        -#   reparse the file, thus readding all the references, and call <AnalyzeChanges()>.
        -#
        -#   <REFERENCE_TEXT> references should *always* be managed with <WatchFileForChanges()> and <AnalyzeChanges()>.
        -#   This function should only be used externally for other types of references.
        -#
        -#   Parameters:
        -#
        -#       referenceString - The <ReferenceString>.
        -#       file - The <FileName> where the reference is.  This is not required unless the type is <REFERENCE_TEXT>.
        -#
        -sub DeleteReference #(referenceString, file)
        -    {
        -    my ($self, $referenceString, $file) = @_;
        -
        -
        -    # If the reference exists...
        -    if (exists $references{$referenceString})
        -        {
        -        my $referenceObject = $references{$referenceString};
        -
        -        if (defined $file)
        -            {  $referenceObject->DeleteDefinition($file);  };
        -
        -        # If there are no other definitions, or it doesn't use file definitions to begin with...
        -        if (!$referenceObject->IsDefined())
        -            {
        -            my @interpretations = $referenceObject->Interpretations();
        -            foreach my $interpretation (@interpretations)
        -                {
        -                $symbols{$interpretation}->DeleteReference($referenceString);
        -                };
        -
        -            delete $references{$referenceString};
        -            };
        -
        -
        -        if (defined $file)
        -            {
        -            # Remove it from the file index.
        -
        -            $files{$file}->DeleteReference($referenceString);
        -
        -            if (!$files{$file}->HasAnything())
        -                {  delete $files{$file};  };
        -
        -            # We don't need to worry about the watched file, since this function will only be called by AnalyzeChanges() and
        -            # LoadAndPurge().
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: RebuildAllIndexes
        -#
        -#   When called, it makes sure all indexes are listed as changed by <IndexChanged()>, regardless of whether they actually did
        -#   or not.
        -#
        -#   This can be called at any time.
        -#
        -sub RebuildAllIndexes
        -    {
        -    my $self = shift;
        -    $rebuildIndexes = 1;
        -    };
        -
        -
        -#
        -#   Function: PurgeResolvingInfo
        -#
        -#   Purges unnecessary information from the symbol table after it is fully resolved.  This will reduce the memory footprint for the
        -#   build stage.  After calling this function, you can only call the <Information Functions> and <Save()>.
        -#
        -sub PurgeResolvingInfo
        -    {
        -    my ($self) = @_;
        -
        -    # Go through the symbols.  We don't need to keep around potential symbols anymore, nor do we need what references can
        -    # be interpreted as the defined ones.
        -
        -    while (my ($symbol, $symbolObject) = each %symbols)
        -        {
        -        if ($symbolObject->IsDefined())
        -            {  $symbolObject->DeleteAllReferences();  }
        -        else
        -            {  delete $symbols{$symbol};  };
        -        };
        -
        -
        -    # Go through the references.  We don't need any of the interpretations except for the current.
        -
        -    foreach my $referenceObject (values %references)
        -        {  $referenceObject->DeleteAllInterpretationsButCurrent();  };
        -
        -
        -    # We don't need the information by file at all.
        -
        -    %files = ( );
        -    };
        -
        -
        -#
        -#   Function: PurgeIndexes
        -#
        -#   Clears all generated indexes.
        -#
        -sub PurgeIndexes
        -    {
        -    my ($self) = @_;
        -    %indexes = ( );
        -    };
        -
        -
        -###############################################################################
        -# Group: Information Functions
        -# These functions should not be called until the symbol table is fully resolved.
        -
        -
        -#
        -#   Function: References
        -#
        -#   Returns what the passed reference information resolve to, if anything.  Note that this only works if the reference had
        -#   been previously added to the table via <AddReference()> with the exact same parameters.
        -#
        -#   Parameters:
        -#
        -#       type     - The <ReferenceType>.
        -#       symbol - The reference <SymbolString>.
        -#       scope   - The scope <SymbolString> the reference appears in, or undef if none.
        -#       using    - An arrayref of scope <SymbolStrings> available to the reference via using statements.
        -#       file       - The source <FileName> the reference appears in, or undef if none.
        -#       resolvingFlags - The <Resolving Flags> of the reference.  Ignored if the type is <REFERENCE_TEXT>.
        -#
        -#   Alternate Parameters:
        -#
        -#       referenceString - The <ReferenceString> to resolve.
        -#       file - The source <FileName> the reference appears in, or undef if none.
        -#
        -#   Returns:
        -#
        -#       A <NaturalDocs::SymbolTable::ReferenceTarget> object, or undef if the reference doesn't resolve to anything.
        -#
        -sub References #(type, symbol, scope, using, file, resolvingFlags) or (referenceString, file)
        -    {
        -    my ($self, $referenceString, $file);
        -
        -    if (scalar @_ <= 3)
        -        {  ($self, $referenceString, $file) = @_;  }
        -    else
        -        {
        -        my ($type, $symbol, $scope, $using, $resolvingFlags);
        -        ($self, $type, $symbol, $scope, $using, $file, $resolvingFlags) = @_;
        -
        -        $referenceString = NaturalDocs::ReferenceString->MakeFrom($type, $symbol,
        -                                                                                                  NaturalDocs::Languages->LanguageOf($file)->Name(),
        -                                                                                                  $scope, $using, $resolvingFlags);
        -        };
        -
        -    if (exists $references{$referenceString} && $references{$referenceString}->HasCurrentInterpretation())
        -        {
        -        my $targetSymbol = $references{$referenceString}->CurrentInterpretation();
        -        my $targetObject = $symbols{$targetSymbol};
        -
        -        my $targetFile;
        -        my $targetType;
        -        my $targetPrototype;
        -        my $targetSummary;
        -
        -        if (defined $file && $targetObject->IsDefinedIn($file))
        -            {
        -            $targetFile = $file;
        -            $targetType = $targetObject->TypeDefinedIn($file);
        -            $targetPrototype = $targetObject->PrototypeDefinedIn($file);
        -            $targetSummary = $targetObject->SummaryDefinedIn($file);
        -            }
        -        else
        -            {
        -            $targetFile = $targetObject->GlobalDefinition();
        -            $targetType = $targetObject->GlobalType();
        -            $targetPrototype = $targetObject->GlobalPrototype();
        -            $targetSummary = $targetObject->GlobalSummary();
        -            };
        -
        -        return NaturalDocs::SymbolTable::ReferenceTarget->New($targetSymbol, $targetFile, $targetType, $targetPrototype,
        -                                                                                             $targetSummary);
        -        }
        -
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: Lookup
        -#
        -#   Returns information on the passed <SymbolString>, if it exists.  Note that the symbol must be fully resolved.
        -#
        -#   Parameters:
        -#
        -#       symbol - The <SymbolString>.
        -#       file - The source <FileName> the reference appears in, or undef if none.
        -#
        -#   Returns:
        -#
        -#       A <NaturalDocs::SymbolTable::ReferenceTarget> object, or undef if the symbol isn't defined.
        -#
        -sub Lookup #(symbol, file)
        -    {
        -    my ($self, $symbol, $file) = @_;
        -
        -    my $symbolObject = $symbols{$symbol};
        -
        -    if (defined $symbolObject)
        -        {
        -        my $targetFile;
        -        my $targetType;
        -        my $targetPrototype;
        -        my $targetSummary;
        -
        -        if (defined $file && $symbolObject->IsDefinedIn($file))
        -            {
        -            $targetFile = $file;
        -            $targetType = $symbolObject->TypeDefinedIn($file);
        -            $targetPrototype = $symbolObject->PrototypeDefinedIn($file);
        -            $targetSummary = $symbolObject->SummaryDefinedIn($file);
        -            }
        -        else
        -            {
        -            $targetFile = $symbolObject->GlobalDefinition();
        -            $targetType = $symbolObject->GlobalType();
        -            $targetPrototype = $symbolObject->GlobalPrototype();
        -            $targetSummary = $symbolObject->GlobalSummary();
        -            };
        -
        -        return NaturalDocs::SymbolTable::ReferenceTarget->New($symbol, $targetFile, $targetType, $targetPrototype,
        -                                                                                             $targetSummary);
        -        }
        -
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: Index
        -#
        -#   Returns a symbol index.
        -#
        -#   Indexes are generated on demand, but they are stored so subsequent calls for the same index will be fast.  Call
        -#   <PurgeIndexes()> to clear the generated indexes.
        -#
        -#   Parameters:
        -#
        -#       type  - The <TopicType> of symbol to limit the index to, or undef for none.
        -#
        -#   Returns:
        -#
        -#       An arrayref of sections.  The first represents all the symbols, the second the numbers, and the rest A through Z.
        -#       Each section is a sorted arrayref of <NaturalDocs::SymbolTable::IndexElement> objects.  If a section has no content,
        -#       it will be undef.
        -#
        -sub Index #(type)
        -    {
        -    my ($self, $type) = @_;
        -
        -    if (!exists $indexes{$type})
        -        {  $indexes{$type} = $self->MakeIndex($type);  };
        -
        -    return $indexes{$type};
        -    };
        -
        -
        -#
        -#   Function: HasIndexes
        -#
        -#   Determines which indexes out of a list actually have content.
        -#
        -#   Parameters:
        -#
        -#       types  - An existence hashref of the <TopicTypes> to check for indexes.
        -#
        -#   Returns:
        -#
        -#       An existence hashref of all the specified indexes that have content.  Will return an empty hashref if none.
        -#
        -sub HasIndexes #(types)
        -    {
        -    my ($self, $types) = @_;
        -
        -    # EliminationHash is a copy of all the types, and the types will be deleted as they are found.  This allows us to quit early if
        -    # we've found all the types because the hash will be empty.  We'll later return the original hash minus what was left over
        -    # in here, which are the ones that weren't found.
        -    my %eliminationHash = %$types;
        -
        -    finddefs:
        -    foreach my $symbolObject (values %symbols)
        -        {
        -        foreach my $definition ($symbolObject->Definitions())
        -            {
        -            delete $eliminationHash{ $symbolObject->TypeDefinedIn($definition) };
        -            delete $eliminationHash{ ::TOPIC_GENERAL() };
        -
        -            if (!scalar keys %eliminationHash)
        -                {  last finddefs;  };
        -            };
        -        };
        -
        -    my $result = { %$types };
        -
        -    foreach my $type (keys %eliminationHash)
        -        {  delete $result->{$type};  };
        -
        -    return $result;
        -    };
        -
        -
        -#
        -#   Function: IndexChanged
        -#
        -#   Returns whether the specified index has changed.
        -#
        -#   Parameters:
        -#
        -#       type  - The <TopicType> to limit the index to.
        -#
        -sub IndexChanged #(TopicType type)
        -    {
        -    my ($self, $type) = @_;
        -    return ($rebuildIndexes || defined $indexChanges{$type});
        -    };
        -
        -
        -#
        -#   Function: IndexSectionsWithContent
        -#
        -#   Returns an arrayref of whether each section of the specified index has content.  The first entry will be for symbols, the second
        -#   for numbers, and the rest A-Z.  Do not change the arrayref.
        -#
        -sub IndexSectionsWithContent #(TopicType type)
        -    {
        -    my ($self, $type) = @_;
        -
        -    if (!exists $indexSectionsWithContent{$type})
        -        {
        -        # This is okay because Index() stores generated indexes.  It's not an expensive operation unless the index was never asked
        -        # for before or it will never be asked for otherwise, and this shouldn't be the case.
        -
        -        my $index = $self->Index($type);
        -        my $content = [ ];
        -
        -        for (my $i = 0; $i < 28; $i++)
        -            {
        -            push @$content, (defined $index->[$i] ? 1 : 0);
        -            };
        -
        -        $indexSectionsWithContent{$type} = $content;
        -        };
        -
        -    return $indexSectionsWithContent{$type};
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Event Handlers
        -
        -
        -#
        -#   Function: OnIndexChange
        -#
        -#   Called whenever a change happens to a symbol that would cause an index to be regenerated.
        -#
        -#   Parameters:
        -#
        -#       type - The <TopicType> of the symbol that caused the change.
        -#
        -sub OnIndexChange #(TopicType type)
        -    {
        -    my ($self, $type) = @_;
        -
        -    $indexChanges{$type} = 1;
        -    $indexChanges{::TOPIC_GENERAL()} = 1;
        -    delete $indexSectionsWithContent{$type};
        -    };
        -
        -
        -#
        -#   Function: OnInterpretationChange
        -#
        -#   Called whenever the current interpretation of a reference changes, meaning it switched from one symbol to another.
        -#
        -#   Parameters:
        -#
        -#       referenceString - The <ReferenceString> whose current interpretation changed.
        -#
        -sub OnInterpretationChange #(referenceString)
        -    {
        -    my ($self, $referenceString) = @_;
        -    my $referenceType = NaturalDocs::ReferenceString->TypeOf($referenceString);
        -
        -    if ($referenceType == ::REFERENCE_TEXT())
        -        {
        -        my @referenceDefinitions = $references{$referenceString}->Definitions();
        -
        -        foreach my $referenceDefinition (@referenceDefinitions)
        -            {
        -            NaturalDocs::Project->RebuildFile($referenceDefinition);
        -            };
        -        }
        -
        -    elsif (NaturalDocs::Constants->IsClassHierarchyReference($referenceType))
        -        {
        -        NaturalDocs::ClassHierarchy->OnInterpretationChange($referenceString);
        -        };
        -    };
        -
        -
        -#
        -#   Function: OnTargetSymbolChange
        -#
        -#   Called whenever the symbol that serves as the interpretation of a reference changes, but the reference still resolves to
        -#   the same symbol.  This would happen if the type, prototype, summary, or which file serves as global definition of the symbol
        -#   changes.
        -#
        -#   Parameters:
        -#
        -#       referenceString - The <ReferenceString> whose interpretation's symbol changed.
        -#
        -sub OnTargetSymbolChange #(referenceString)
        -    {
        -    my ($self, $referenceString) = @_;
        -    my $referenceType = NaturalDocs::ReferenceString->TypeOf($referenceString);
        -
        -    if ($referenceType == ::REFERENCE_TEXT())
        -        {
        -        my @referenceDefinitions = $references{$referenceString}->Definitions();
        -
        -        foreach my $referenceDefinition (@referenceDefinitions)
        -            {
        -            NaturalDocs::Project->RebuildFile($referenceDefinition);
        -            };
        -        }
        -
        -    elsif (NaturalDocs::Constants->IsClassHierarchyReference($referenceType))
        -        {
        -        NaturalDocs::ClassHierarchy->OnTargetSymbolChange($referenceString);
        -        };
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -
        -#
        -#   Function: DeleteSymbol
        -#
        -#   Removes a symbol definition from the table.  It will call <OnInterpretationChange()> for all references that have it as their
        -#   current interpretation.
        -#
        -#   External code should not attempt to delete symbols using this function.  Instead it should call <WatchFileFoChanges()>,
        -#   reparse the file, and call <AnalyzeChanges()>.
        -#
        -#   Parameters:
        -#
        -#       symbol - The <SymbolString>.
        -#       file       - The <FileName> where the definition is.
        -#
        -sub DeleteSymbol #(symbol, file)
        -    {
        -    my ($self, $symbol, $file) = @_;
        -
        -
        -    # If the symbol and definition exist...
        -    if (exists $symbols{$symbol} && $symbols{$symbol}->IsDefinedIn($file))
        -        {
        -        my $symbolObject = $symbols{$symbol};
        -        my $wasGlobal = ($symbolObject->GlobalDefinition() eq $file);
        -
        -        $self->OnIndexChange($symbolObject->TypeDefinedIn($file));
        -
        -        $symbolObject->DeleteDefinition($file);
        -
        -        # If this was one definition of many...
        -        if ($symbolObject->IsDefined())
        -            {
        -
        -            # If this was the global definition...
        -            if ($wasGlobal)
        -                {
        -                # Update every file that referenced the global symbol; i.e. every file that doesn't have its own definition.
        -
        -                my @references = $symbolObject->References();
        -
        -                foreach my $reference (@references)
        -                    {
        -                    if ($references{$reference}->CurrentInterpretation() eq $symbol)
        -                        {
        -                        $self->OnTargetSymbolChange($reference);
        -                        };
        -                    };
        -                }
        -
        -            # If this wasn't the global definition...
        -            else
        -                {
        -                # It's a safe bet that we don't need to do anything here.  The only thing that we even need to look for here is if the
        -                # file referenced its own symbol and thus should be rebuilt.  However, if the file is having a symbol deleted, it either
        -                # changed or was itself deleted.  If it changed and still has other Natural Docs content, it should already be on the
        -                # rebuild list.  If it was deleted or no longer has Natural Docs content, we certainly don't want to add it to the rebuild
        -                # list.
        -                };
        -            }
        -
        -        # If this is the only definition...
        -        else
        -            {
        -            # If this symbol is the interpretation of any references...
        -            if ($symbolObject->HasReferences())
        -                {
        -                # If this was the current interpretation of any references, reinterpret them and rebuild their files.
        -
        -                my @references = $symbolObject->References();
        -
        -                foreach my $reference (@references)
        -                    {
        -                    if ($references{$reference}->CurrentInterpretation() eq $symbol)
        -                        {
        -                        $self->InterpretReference($reference);
        -                        $self->OnInterpretationChange($reference);
        -                        };
        -                    };
        -                }
        -
        -            # If there are no interpretations of the symbol...
        -            else
        -                {
        -                # Delete the symbol entirely.
        -                delete $symbols{$symbol};
        -                };
        -            };
        -
        -        # Remove it from the file index.
        -
        -        $files{$file}->DeleteSymbol($symbol);
        -
        -        if (!$files{$file}->HasAnything())
        -            {  delete $files{$file};  };
        -
        -
        -        # We don't need to worry about the watched file, since this function will only be called by AnalyzeChanges() and
        -        # LoadAndPurge().
        -        };
        -    };
        -
        -
        -#
        -#   Function: GenerateInterpretations
        -#
        -#   Generates the list of interpretations for the passed reference.  Also creates potential symbols as necessary.
        -#
        -#   Parameters:
        -#
        -#       referenceString - The <ReferenceString> to generate the interpretations of.
        -#
        -sub GenerateInterpretations #(referenceString)
        -    {
        -    my ($self, $referenceString) = @_;
        -
        -    my ($type, $symbol, $languageName, $scope, $using, $resolvingFlags) =
        -        NaturalDocs::ReferenceString->InformationOf($referenceString);
        -
        -    # RESOLVE_NOPLURAL is handled by having @singulars be empty.
        -    my @singulars;
        -    if (!($resolvingFlags & ::RESOLVE_NOPLURAL()))
        -        {  @singulars = $self->SingularInterpretationsOf($symbol);  };
        -
        -    # Since higher scores are better, we'll start at a high number and decrement.
        -    my $score = 50000;
        -
        -
        -    # If RESOLVE_RELATIVE is set, we do all the scope relatives before the global.
        -    if ($resolvingFlags & ::RESOLVE_RELATIVE())
        -        {
        -        $score = $self->GenerateRelativeInterpretations($referenceString, $symbol, \@singulars, $scope, $score);
        -        }
        -
        -    # If neither RESOLVE_RELATIVE nor RESOLVE_ABSOLUTE is set, we only do the local before the global.
        -    elsif (!($resolvingFlags & ::RESOLVE_ABSOLUTE()))
        -        {
        -        $self->AddInterpretation($referenceString, NaturalDocs::SymbolString->Join($scope, $symbol), $score);
        -        $score--;
        -
        -        foreach my $singular (@singulars)
        -            {
        -            $self->AddInterpretation($referenceString, NaturalDocs::SymbolString->Join($scope, $singular), $score);
        -            $score--;
        -            };
        -        };
        -
        -
        -    # Do the global.
        -
        -    $self->AddInterpretation($referenceString, $symbol, $score);
        -    $score--;
        -
        -    foreach my $singular (@singulars)
        -        {
        -        $self->AddInterpretation($referenceString, $singular, $score);
        -        $score--;
        -        };
        -
        -
        -    # If neither RESOLVE_RELATIVE nor RESOLVE_ABSOLUTE is set, we need to do the rest of the scope relatives after the global.
        -    if (!($resolvingFlags & ::RESOLVE_RELATIVE()) && !($resolvingFlags & ::RESOLVE_ABSOLUTE()))
        -        {
        -        $score = $self->GenerateRelativeInterpretations($referenceString, $symbol, \@singulars, $scope, $score, 1);
        -        };
        -
        -
        -    # Finally, if RESOLVE_NOUSING isn't set, go through the using scopes.
        -    if (!($resolvingFlags & ::RESOLVE_NOUSING()) && defined $using)
        -        {
        -        foreach my $usingScope (@$using)
        -            {
        -            if ($resolvingFlags & ::RESOLVE_ABSOLUTE())
        -                {
        -                $self->AddInterpretation($referenceString, NaturalDocs::SymbolString->Join($usingScope, $symbol), $score);
        -                $score--;
        -
        -                foreach my $singular (@singulars)
        -                    {
        -                    $self->AddInterpretation($referenceString, NaturalDocs::SymbolString->Join($usingScope, $singular), $score);
        -                    $score--;
        -                    };
        -                }
        -            else
        -                {
        -                $score = $self->GenerateRelativeInterpretations($referenceString, $symbol, \@singulars, $usingScope, $score);
        -                };
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: GenerateRelativeInterpretations
        -#
        -#   Generates the list of relative interpretations for the passed reference and packages.  Also creates potential symbols as
        -#   necessary.
        -#
        -#   This function will _not_ create global interpretations.  It _will_ create a local interpretations (symbol + all packages) unless
        -#   you set dontUseFull.
        -#
        -#   Parameters:
        -#
        -#       referenceString - The <ReferenceString> to generate interpretations for.
        -#       symbol - The <SymbolString> to generate interpretations of.
        -#       singulars - A reference to an array of singular <SymbolStrings> to also generate interpretations of.  Set to an empty array
        -#                       if none.
        -#       package - The package <SymbolString> to use.  May be undef.
        -#       score - The starting score to apply.
        -#       dontUseFull - Whether to not generate an interpretation including the full package identifier.  If set, generated interpretations
        -#                           will start one level down.
        -#
        -#   Returns:
        -#
        -#       The next unused score.  This is basically the passed score minus the number of interpretations created.
        -#
        -sub GenerateRelativeInterpretations #(referenceString, symbol, singulars, package, score, dontUseFull)
        -    {
        -    my ($self, $referenceString, $symbol, $singulars, $package, $score, $dontUseFull) = @_;
        -
        -    my @packages = NaturalDocs::SymbolString->IdentifiersOf($package);
        -
        -    # The last package index to include.  This number is INCLUSIVE!
        -    my $packageLevel = scalar @packages - 1;
        -
        -    if ($dontUseFull)
        -        {  $packageLevel--;  };
        -
        -    while ($packageLevel >= 0)
        -        {
        -        $self->AddInterpretation($referenceString, NaturalDocs::SymbolString->Join(@packages[0..$packageLevel], $symbol),
        -                                             $score);
        -        $score--;
        -
        -        foreach my $singular (@$singulars)
        -            {
        -            $self->AddInterpretation($referenceString, NaturalDocs::SymbolString->Join(@packages[0..$packageLevel], $singular),
        -                                                 $score);
        -            $score--;
        -            };
        -
        -        $packageLevel--;
        -        };
        -
        -    return $score;
        -    };
        -
        -
        -#
        -#   Function: SingularInterpretationsOf
        -#
        -#   Generates singular interpretations of a <SymbolString> if it can be interpreted as a plural.  Not all of them will be valid singular
        -#   forms, but that doesn't matter since it's incredibly unlikely an invalid form would exist as a symbol.  What matters is that the
        -#   legimate singular is present on the list.
        -#
        -#   Parameters:
        -#
        -#       symbol - The <SymbolString>.
        -#
        -#   Returns:
        -#
        -#       An array of potential singular interpretations as <SymbolStrings>, in no particular order.  If the symbol can't be interpreted
        -#       as a plural, returns an empty array.
        -#
        -sub SingularInterpretationsOf #(symbol)
        -    {
        -    my ($self, $symbol) = @_;
        -
        -    my @identifiers = NaturalDocs::SymbolString->IdentifiersOf($symbol);
        -    my $lastIdentifier = pop @identifiers;
        -    my $preIdentifiers = NaturalDocs::SymbolString->Join(@identifiers);
        -
        -    my @results;
        -
        -    # First cut off any 's or ' at the end, since they can appear after other plural forms.
        -    if ($lastIdentifier =~ s/\'s?$//i)
        -        {
        -        push @results, NaturalDocs::SymbolString->Join($preIdentifiers, $lastIdentifier);
        -        };
        -
        -    # See http://www.gsu.edu/~wwwesl/egw/crump.htm for a good list of potential plural forms.  There are a couple more than
        -    # listed below, but they're fairly rare and this is already seriously over-engineered.  This is split by suffix length to make
        -    # comparisons more efficient.
        -
        -    # The fact that this will generate some impossible combinations (leaves => leave, leav, leaf, leafe) doesn't matter.  It's very
        -    # unlikely that more than one will manage to match a defined symbol.  Even if they do (leave, leaf), it's incredibly unlikely
        -    # that someone has defined an impossible one (leav, leafe).  So it's not so important that we remove impossible combinations,
        -    # just that we include all the possible ones.
        -
        -    my @suffixGroups = ( [ 's', undef,  # boys => boy
        -                                       'i', 'us',  # alumni => alumnus
        -                                       'a', 'um', # errata => erratum
        -                                       'a', 'on' ],  # phenomena => phenomenon
        -
        -                                    [ 'es', undef,  # foxes => fox
        -                                      'ae', 'a' ],  # amoebae => amoeba
        -
        -                                    [ 'ies', 'y',  # pennies => penny
        -                                      'ves', 'f',  # calves => calf
        -                                      'ves', 'fe',  # knives => knife
        -                                      'men', 'man',  # women => woman
        -                                      'ice', 'ouse',  # mice => mouse
        -                                      'oes', 'o',  # vetoes => veto
        -                                      'ces', 'x',  # matrices => matrix
        -                                      'xen', 'x' ],  # oxen => ox
        -
        -                                    [ 'ices', 'ex',  # indices => index
        -                                      'feet', 'foot',  # feet => foot
        -                                      'eese', 'oose',  # geese => goose
        -                                      'eeth', 'ooth',  # teeth => tooth
        -                                      'dren', 'd' ] );  # children => child
        -
        -    my $suffixLength = 1;
        -
        -    foreach my $suffixGroup (@suffixGroups)
        -        {
        -        my $identifierSuffix = lc( substr($lastIdentifier, 0 - $suffixLength) );
        -        my $cutIdentifier = substr($lastIdentifier, 0, 0 - $suffixLength);
        -
        -        for (my $i = 0; $i + 1 < scalar @$suffixGroup; $i += 2)
        -            {
        -            my $suffix = $suffixGroup->[$i];
        -            my $replacement = $suffixGroup->[$i + 1];
        -
        -            if ($identifierSuffix eq $suffix)
        -                {
        -                if (defined $replacement)
        -                    {
        -                    push @results, NaturalDocs::SymbolString->Join($preIdentifiers, $cutIdentifier . $replacement);
        -                    push @results, NaturalDocs::SymbolString->Join($preIdentifiers, $cutIdentifier . uc($replacement));
        -                    }
        -                else
        -                    {
        -                    push @results, NaturalDocs::SymbolString->Join($preIdentifiers, $cutIdentifier);
        -                    };
        -                };
        -            };
        -
        -        $suffixLength++;
        -        };
        -
        -    return @results;
        -    };
        -
        -
        -#
        -#   Function: AddInterpretation
        -#
        -#   Adds an interpretation to an existing reference.  Creates potential symbols as necessary.
        -#
        -#   Parameters:
        -#
        -#       referenceString - The <ReferenceString> to add the interpretation to.
        -#       symbol - The <SymbolString> the reference can be interpreted as.
        -#       score - The score of the interpretation.
        -#
        -sub AddInterpretation #(referenceString, symbol, score)
        -    {
        -    my ($self, $referenceString, $symbol, $score) = @_;
        -
        -    $references{$referenceString}->AddInterpretation($symbol, $score);
        -
        -    # Create a potential symbol if it doesn't exist.
        -
        -    if (!exists $symbols{$symbol})
        -        {  $symbols{$symbol} = NaturalDocs::SymbolTable::Symbol->New();  };
        -
        -    $symbols{$symbol}->AddReference($referenceString, $score);
        -    };
        -
        -
        -#
        -#   Function: InterpretReference
        -#
        -#   Interprets the passed reference, matching it to the defined symbol with the highest score.  If the symbol is already
        -#   interpreted, it will reinterpret it.  If there are no matches, it will make it an undefined reference.
        -#
        -#   Parameters:
        -#
        -#       referenceString - The <ReferenceString> to interpret.
        -#
        -sub InterpretReference #(referenceString)
        -    {
        -    my ($self, $referenceString) = @_;
        -
        -    my $interpretation;
        -    my $currentInterpretation;
        -    my $score;
        -    my $currentScore = -1;
        -
        -    my $referenceObject = $references{$referenceString};
        -
        -    my %interpretationsAndScores = $referenceObject->InterpretationsAndScores();
        -    while ( ($interpretation, $score) = each %interpretationsAndScores )
        -        {
        -        if ($score > $currentScore && $symbols{$interpretation}->IsDefined())
        -            {
        -            $currentScore = $score;
        -            $currentInterpretation = $interpretation;
        -            };
        -        };
        -
        -    if ($currentScore > -1)
        -        {  $referenceObject->SetCurrentInterpretation($currentInterpretation);  }
        -    else
        -        {  $referenceObject->SetCurrentInterpretation(undef);  };
        -    };
        -
        -
        -#
        -#   Function: MakeIndex
        -#
        -#   Generates a symbol index.
        -#
        -#   Parameters:
        -#
        -#       type  - The <TopicType> to limit the index to.
        -#
        -#   Returns:
        -#
        -#       An arrayref of sections.  The first represents all the symbols, the second the numbers, and the rest A through Z.
        -#       Each section is a sorted arrayref of <NaturalDocs::SymbolTable::IndexElement> objects.  If a section has no content,
        -#       it will be undef.
        -#
        -sub MakeIndex #(type)
        -    {
        -    my ($self, $type) = @_;
        -
        -
        -    # Go through the symbols and generate IndexElements for any that belong in the index.
        -
        -    # Keys are the symbol strings, values are IndexElements.
        -    my %indexSymbols;
        -
        -    while (my ($symbolString, $object) = each %symbols)
        -        {
        -        my ($symbol, $package) = $self->SplitSymbolForIndex($symbolString, $object->GlobalType());
        -        my @definitions = $object->Definitions();
        -
        -        foreach my $definition (@definitions)
        -            {
        -            my $definitionType = $object->TypeDefinedIn($definition);
        -
        -            if ($type eq ::TOPIC_GENERAL() || $type eq $definitionType)
        -                {
        -                if (!exists $indexSymbols{$symbol})
        -                    {
        -                    $indexSymbols{$symbol} =
        -                        NaturalDocs::SymbolTable::IndexElement->New($symbol, $package, $definition, $definitionType,
        -                                                                                               $object->PrototypeDefinedIn($definition),
        -                                                                                               $object->SummaryDefinedIn($definition) );
        -                    }
        -                else
        -                    {
        -                    $indexSymbols{$symbol}->Merge($package, $definition, $definitionType,
        -                                                                       $object->PrototypeDefinedIn($definition),
        -                                                                       $object->SummaryDefinedIn($definition) );
        -                    };
        -                }; # If type matches
        -            }; # Each definition
        -        }; # Each symbol
        -
        -
        -    # Generate sortable symbols for each IndexElement, sort them internally, and divide them into sections.
        -
        -    my $sections = [ ];
        -
        -    foreach my $indexElement (values %indexSymbols)
        -        {
        -        $indexElement->Sort();
        -        $indexElement->MakeSortableSymbol();
        -
        -        my $sectionNumber;
        -
        -        if ($indexElement->SortableSymbol() =~ /^([a-z])/i)
        -            {  $sectionNumber = ord(lc($1)) - ord('a') + 2;  }
        -        elsif ($indexElement->SortableSymbol() =~ /^[0-9]/)
        -            {  $sectionNumber = 1;  }
        -        else
        -            {  $sectionNumber = 0;  };
        -
        -        if (!defined $sections->[$sectionNumber])
        -            {  $sections->[$sectionNumber] = [ ];  };
        -
        -        push @{$sections->[$sectionNumber]}, $indexElement;
        -        };
        -
        -
        -    # Sort each section.
        -
        -    for (my $i = 0; $i < scalar @$sections; $i++)
        -        {
        -        if (defined $sections->[$i])
        -            {
        -            @{$sections->[$i]} = sort
        -                {
        -                my $result = ::StringCompare($a->SortableSymbol(), $b->SortableSymbol());
        -
        -                if ($result == 0)
        -                    {  $result = ::StringCompare($a->IgnoredPrefix(), $b->IgnoredPrefix());  };
        -
        -                return $result;
        -                }
        -            @{$sections->[$i]};
        -            };
        -        };
        -
        -    return $sections;
        -    };
        -
        -
        -#
        -#   Function: SplitSymbolForIndex
        -#
        -#   Splits a <SymbolString> into its symbol and package portions for indexing.
        -#
        -#   Parameters:
        -#
        -#       symbol - The <SymbolString>.
        -#       type - Its <TopicType>.
        -#
        -#   Returns:
        -#
        -#       The array ( symbol, package ), which are both <SymbolStrings>.  If the symbol is global, package will be undef.
        -#
        -sub SplitSymbolForIndex #(symbol, type)
        -    {
        -    my ($self, $symbol, $type) = @_;
        -
        -    my $scope = NaturalDocs::Topics->TypeInfo($type)->Scope();
        -
        -    if ($scope == ::SCOPE_START() || $scope == ::SCOPE_ALWAYS_GLOBAL())
        -        {  return ( $symbol, undef );  }
        -    else
        -        {
        -        my @identifiers = NaturalDocs::SymbolString->IdentifiersOf($symbol);
        -
        -        $symbol = pop @identifiers;
        -        my $package = NaturalDocs::SymbolString->Join(@identifiers);
        -
        -        return ( $symbol, $package );
        -        };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/File.pm b/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/File.pm
        deleted file mode 100644
        index f07c8c939..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/File.pm
        +++ /dev/null
        @@ -1,187 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::SymbolTable::File
        -#
        -###############################################################################
        -#
        -#   A class representing a file, keeping track of what symbols and references are defined in it.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::SymbolTable::File;
        -
        -
        -###############################################################################
        -# Group: Implementation
        -
        -#
        -#   Constants: Members
        -#
        -#   The class is implemented as a blessed arrayref.  The following constants are its members.
        -#
        -#       SYMBOLS       - An existence hashref of the <SymbolStrings> it defines.
        -#       REFERENCES  - An existence hashref of the <ReferenceStrings> in the file.
        -#
        -
        -# DEPENDENCY: New() depends on the order of these constants.  If they change, New() has to be updated.
        -use constant SYMBOLS => 0;
        -use constant REFERENCES => 1;
        -
        -
        -###############################################################################
        -# Group: Modification Functions
        -
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -sub New
        -    {
        -    my $package = shift;
        -
        -    # Let's make it safe, since normally you can pass values to New.  Having them just be ignored would be an obscure error.
        -    if (scalar @_)
        -        {  die "You can't pass values to NaturalDocs::SymbolTable::File->New()\n";  };
        -
        -    # DEPENDENCY: This code depends on the order of the member constants.
        -    my $object = [ { }, { } ];
        -    bless $object, $package;
        -
        -    return $object;
        -    };
        -
        -
        -#
        -#   Function: AddSymbol
        -#
        -#   Adds a <SymbolString> definition.
        -#
        -#   Parameters:
        -#
        -#       symbol - The <SymbolString> being added.
        -#
        -sub AddSymbol #(symbol)
        -    {
        -    my ($self, $symbol) = @_;
        -    $self->[SYMBOLS]{$symbol} = 1;
        -    };
        -
        -
        -#
        -#   Function: DeleteSymbol
        -#
        -#   Removes a <SymbolString> definition.
        -#
        -#   Parameters:
        -#
        -#       symbol - The <SymbolString> to delete.
        -#
        -sub DeleteSymbol #(symbol)
        -    {
        -    my ($self, $symbol) = @_;
        -    delete $self->[SYMBOLS]{$symbol};
        -    };
        -
        -
        -#
        -#   Function: AddReference
        -#
        -#   Adds a reference definition.
        -#
        -#   Parameters:
        -#
        -#       referenceString - The <ReferenceString> being added.
        -#
        -sub AddReference #(referenceString)
        -    {
        -    my ($self, $referenceString) = @_;
        -    $self->[REFERENCES]{$referenceString} = 1;
        -    };
        -
        -
        -#
        -#   Function: DeleteReference
        -#
        -#   Removes a reference definition.
        -#
        -#   Parameters:
        -#
        -#       referenceString - The <ReferenceString> to delete.
        -#
        -sub DeleteReference #(referenceString)
        -    {
        -    my ($self, $referenceString) = @_;
        -    delete $self->[REFERENCES]{$referenceString};
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Information Functions
        -
        -
        -#
        -#   Function: HasAnything
        -#
        -#   Returns whether the file has any symbol or reference definitions at all.
        -#
        -sub HasAnything
        -    {
        -    return (scalar keys %{$_[0]->[SYMBOLS]} || scalar keys %{$_[0]->[REFERENCES]});
        -    };
        -
        -#
        -#   Function: Symbols
        -#
        -#   Returns an array of all the <SymbolStrings> defined in this file.  If none, returns an empty array.
        -#
        -sub Symbols
        -    {
        -    return keys %{$_[0]->[SYMBOLS]};
        -    };
        -
        -
        -#
        -#   Function: References
        -#
        -#   Returns an array of all the <ReferenceStrings> defined in this file.  If none, returns an empty array.
        -#
        -sub References
        -    {
        -    return keys %{$_[0]->[REFERENCES]};
        -    };
        -
        -
        -#
        -#   Function: DefinesSymbol
        -#
        -#   Returns whether the file defines the passed <SymbolString> or not.
        -#
        -sub DefinesSymbol #(symbol)
        -    {
        -    my ($self, $symbol) = @_;
        -    return exists $self->[SYMBOLS]{$symbol};
        -    };
        -
        -
        -#
        -#   Function: DefinesReference
        -#
        -#   Returns whether the file defines the passed <ReferenceString> or not.
        -#
        -sub DefinesReference #(referenceString)
        -    {
        -    my ($self, $referenceString) = @_;
        -    return exists $self->[REFERENCES]{$referenceString};
        -    };
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/IndexElement.pm b/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/IndexElement.pm
        deleted file mode 100644
        index ee6a9e8cc..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/IndexElement.pm
        +++ /dev/null
        @@ -1,523 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::SymbolTable::IndexElement
        -#
        -###############################################################################
        -#
        -#   A class representing part of an indexed symbol.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use Tie::RefHash;
        -
        -use strict;
        -use integer;
        -
        -
        -package NaturalDocs::SymbolTable::IndexElement;
        -
        -
        -#
        -#   Topic: How IndexElements Work
        -#
        -#   This is a little tricky, so make sure you understand this.  Indexes are sorted by symbol, then packages, then file.  If there is only
        -#   one package for a symbol, or one file definition for a package/symbol, they are added inline to the entry.  However, if there are
        -#   multiple packages or files, the function for it returns an arrayref of IndexElements instead.  Which members are defined and
        -#   undefined should follow common sense.  For example, if a symbol is defined in multiple packages, the symbol's IndexElement
        -#   will not define <File()>, <Type()>, or <Prototype()>; those will be defined in child elements.  Similarly, the child elements will
        -#   not define <Symbol()> since it's redundant.
        -#
        -#   Diagrams may be clearer.  If a member isn't listed for an element, it isn't defined.
        -#
        -#   A symbol that only has one package and file:
        -#   > [Element]
        -#   > - Symbol
        -#   > - Package
        -#   > - File
        -#   > - Type
        -#   > - Prototype
        -#   > - Summary
        -#
        -#   A symbol that is defined by multiple packages, each with only one file:
        -#   > [Element]
        -#   > - Symbol
        -#   > - Package
        -#   >     [Element]
        -#   >     - Package
        -#   >     - File
        -#   >     - Type
        -#   >     - Prototype
        -#   >     - Summary
        -#   >     [Element]
        -#   >     - ...
        -#
        -#   A symbol that is defined by one package, but has multiple files
        -#   > [Element]
        -#   > - Symbol
        -#   > - Package
        -#   > - File
        -#   >    [Element]
        -#   >    - File
        -#   >    - Type
        -#   >    - Protype
        -#   >    - Summary
        -#   >    [Element]
        -#   >    - ...
        -#
        -#   A symbol that is defined by multiple packages which have multiple files:
        -#   > [Element]
        -#   > - Symbol
        -#   > - Package
        -#   >    [Element]
        -#   >    - Package
        -#   >    - File
        -#   >      [Element]
        -#   >      - File
        -#   >      - Type
        -#   >      - Prototype
        -#   >      - Summary
        -#   >      [Element]
        -#   >      - ...
        -#   >    [Element]
        -#   >    - ...
        -#
        -#   Why is it done this way?:
        -#
        -#   Because it makes it easier to generate nice indexes since all the splitting and combining is done for you.  If a symbol
        -#   has only one package, you just want to link to it, you don't want to break out a subindex for just one package.  However, if
        -#   it has multiple package, you do want the subindex and to link to each one individually.  Use <HasMultiplePackages()> and
        -#   <HasMultipleFiles()> to determine whether you need to add a subindex for it.
        -#
        -#
        -#   Combining Properties:
        -#
        -#   All IndexElements also have combining properties set.
        -#
        -#   CombinedType - The general <TopicType> of the entry.  Conflicts combine into <TOPIC_GENERAL>.
        -#   PackageSeparator - The package separator symbol of the entry.  Conflicts combine into a dot.
        -#
        -#   So if an IndexElement only has one definition, <CombinedType()> is the same as the <TopicType> and <PackageSeparator()>
        -#   is that of the definition's language.  If other definitions are added and they have the same properties, the combined properties
        -#   will remain the same.  However, if they're different, they switch values as noted above.
        -#
        -#
        -#   Sortable Symbol:
        -#
        -#   <SortableSymbol()> is a pseudo-combining property.  There were a few options for dealing with multiple languages defining
        -#   the same symbol but stripping different prefixes off it, but ultimately I decided to go with whatever the language does that
        -#   has the most definitions.  There's not likely to be many conflicts here in the real world; probably the only thing would be
        -#   defining it in a text file and forgetting to specify the prefixes to strip there too.  So this works.
        -#
        -#   Ties are broken pretty much randomly, except that text files always lose if its one of the options.
        -#
        -#   It's a pseudo-combining property because it's done after the IndexElements are all filled in and only stored in the top-level
        -#   ones.
        -#
        -
        -
        -###############################################################################
        -# Group: Implementation
        -
        -#
        -#   Constants: Members
        -#
        -#   The class is implemented as a blessed arrayref.  The following constants are its members.
        -#
        -#   SYMBOL - The <SymbolString> without the package portion.
        -#   PACKAGE - The package <SymbolString>.  Will be a package <SymbolString>, undef for global, or an arrayref of
        -#                    <NaturalDocs::SymbolTable::IndexElement> objects if multiple packages define the symbol.
        -#   FILE - The <FileName> the package/symbol is defined in.  Will be the file name or an arrayref of
        -#            <NaturalDocs::SymbolTable::IndexElements> if multiple files define the package/symbol.
        -#   TYPE - The package/symbol/file <TopicType>.
        -#   PROTOTYPE - The package/symbol/file prototype, or undef if not applicable.
        -#   SUMMARY - The package/symbol/file summary, or undef if not applicable.
        -#   COMBINED_TYPE - The combined <TopicType> of the element.
        -#   PACKAGE_SEPARATOR - The combined package separator symbol of the element.
        -#   SORTABLE_SYMBOL - The sortable symbol as a text string.
        -#   IGNORED_PREFIX - The part of the symbol that was stripped off to make the sortable symbol.
        -#
        -use NaturalDocs::DefineMembers 'SYMBOL', 'Symbol()',
        -                                                 'PACKAGE', 'Package()',
        -                                                 'FILE', 'File()',
        -                                                 'TYPE', 'Type()',
        -                                                 'PROTOTYPE', 'Prototype()',
        -                                                 'SUMMARY', 'Summary()',
        -                                                 'COMBINED_TYPE', 'CombinedType()',
        -                                                 'PACKAGE_SEPARATOR', 'PackageSeparator()',
        -                                                 'SORTABLE_SYMBOL', 'SortableSymbol()',
        -                                                 'IGNORED_PREFIX', 'IgnoredPrefix()';
        -# DEPENDENCY: New() depends on the order of these constants and that there is no inheritance..
        -
        -
        -###############################################################################
        -# Group: Modification Functions
        -
        -#
        -#   Function: New
        -#
        -#   Returns a new object.
        -#
        -#   This should only be used for creating an entirely new symbol.  You should *not* pass arrayrefs as package or file parameters
        -#   if you are calling this externally.  Use <Merge()> instead.
        -#
        -#   Parameters:
        -#
        -#       symbol  - The <SymbolString> without the package portion.
        -#       package - The package <SymbolString>, or undef for global.
        -#       file  - The symbol's definition file.
        -#       type  - The symbol's <TopicType>.
        -#       prototype  - The symbol's prototype, if applicable.
        -#       summary  - The symbol's summary, if applicable.
        -#
        -#   Optional Parameters:
        -#
        -#       These parameters don't need to be specified.  You should ignore them when calling this externally.
        -#
        -#       combinedType - The symbol's combined <TopicType>.
        -#       packageSeparator - The symbol's combined package separator symbol.
        -#
        -sub New #(symbol, package, file, type, prototype, summary, combinedType, packageSeparator)
        -    {
        -    # DEPENDENCY: This depends on the parameter list being in the same order as the constants.
        -
        -    my $self = shift;
        -
        -    my $object = [ @_ ];
        -    bless $object, $self;
        -
        -    if (!defined $object->[COMBINED_TYPE])
        -        {  $object->[COMBINED_TYPE] = $object->[TYPE];  };
        -
        -    if (!defined $object->[PACKAGE_SEPARATOR])
        -        {
        -        if ($object->[TYPE] eq ::TOPIC_FILE())
        -            {  $object->[PACKAGE_SEPARATOR] = '.';  }
        -        else
        -            {
        -            $object->[PACKAGE_SEPARATOR] = NaturalDocs::Languages->LanguageOf($object->[FILE])->PackageSeparator();
        -            };
        -        };
        -
        -    return $object;
        -    };
        -
        -
        -#
        -#   Function: Merge
        -#
        -#   Adds another definition of the same symbol.  Perhaps it has a different package or defining file.
        -#
        -#   Parameters:
        -#
        -#       package - The package <SymbolString>, or undef for global.
        -#       file  - The symbol's definition file.
        -#       type  - The symbol's <TopicType>.
        -#       prototype  - The symbol's protoype if applicable.
        -#       summary  - The symbol's summary if applicable.
        -#
        -sub Merge #(package, file, type, prototype, summary)
        -    {
        -    my ($self, $package, $file, $type, $prototype, $summary) = @_;
        -
        -    # If there's only one package...
        -    if (!$self->HasMultiplePackages())
        -        {
        -        # If there's one package and it's the same as the new one...
        -        if ($package eq $self->Package())
        -            {
        -            $self->MergeFile($file, $type, $prototype, $summary);
        -            }
        -
        -        # If there's one package and the new one is different...
        -        else
        -            {
        -            my $selfDefinition = NaturalDocs::SymbolTable::IndexElement->New(undef, $self->Package(), $self->File(),
        -                                                                                                                 $self->Type(), $self->Prototype(),
        -                                                                                                                 $self->Summary(), $self->CombinedType(),
        -                                                                                                                 $self->PackageSeparator());
        -            my $newDefinition = NaturalDocs::SymbolTable::IndexElement->New(undef, $package, $file, $type, $prototype,
        -                                                                                                                  $summary);
        -
        -            $self->[PACKAGE] = [ $selfDefinition, $newDefinition ];
        -            $self->[FILE] = undef;
        -            $self->[TYPE] = undef;
        -            $self->[PROTOTYPE] = undef;
        -            $self->[SUMMARY] = undef;
        -
        -            if ($newDefinition->Type() ne $self->CombinedType())
        -                {  $self->[COMBINED_TYPE] = ::TOPIC_GENERAL();  };
        -            if ($newDefinition->PackageSeparator() ne $self->PackageSeparator())
        -                {  $self->[PACKAGE_SEPARATOR] = '.';  };
        -            };
        -        }
        -
        -    # If there's more than one package...
        -    else
        -        {
        -        # See if the new package is one of them.
        -        my $selfPackages = $self->Package();
        -        my $matchingPackage;
        -
        -        foreach my $testPackage (@$selfPackages)
        -            {
        -            if ($package eq $testPackage->Package())
        -                {
        -                $testPackage->MergeFile($file, $type, $prototype, $summary);;
        -                return;
        -                };
        -            };
        -
        -        my $newDefinition = NaturalDocs::SymbolTable::IndexElement->New(undef, $package, $file, $type, $prototype,
        -                                                                                                              $summary);
        -        push @{$self->[PACKAGE]}, $newDefinition;
        -
        -        if ($newDefinition->Type() ne $self->CombinedType())
        -            {  $self->[COMBINED_TYPE] = ::TOPIC_GENERAL();  };
        -        if ($newDefinition->PackageSeparator() ne $self->PackageSeparator())
        -            {  $self->[PACKAGE_SEPARATOR] = '.';  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: Sort
        -#
        -#   Sorts the package and file lists of the symbol.
        -#
        -sub Sort
        -    {
        -    my $self = shift;
        -
        -    if ($self->HasMultipleFiles())
        -        {
        -        @{$self->[FILE]} = sort { ::StringCompare($a->File(), $b->File()) } @{$self->File()};
        -        }
        -
        -    elsif ($self->HasMultiplePackages())
        -        {
        -        @{$self->[PACKAGE]} = sort { ::StringCompare( $a->Package(), $b->Package()) } @{$self->[PACKAGE]};
        -
        -        foreach my $packageElement ( @{$self->[PACKAGE]} )
        -            {
        -            if ($packageElement->HasMultipleFiles())
        -                {  $packageElement->Sort();  };
        -            };
        -        };
        -    };
        -
        -
        -#
        -#   Function: MakeSortableSymbol
        -#
        -#   Generates <SortableSymbol()> and <IgnoredPrefix()>.  Should only be called after everything is merged.
        -#
        -sub MakeSortableSymbol
        -    {
        -    my $self = shift;
        -
        -    my $finalLanguage;
        -
        -    if ($self->HasMultiplePackages() || $self->HasMultipleFiles())
        -        {
        -        # Collect all the files that define this symbol.
        -
        -        my @files;
        -
        -        if ($self->HasMultipleFiles())
        -            {
        -            my $fileElements = $self->File();
        -
        -            foreach my $fileElement (@$fileElements)
        -                {  push @files, $fileElement->File();  };
        -            }
        -        else # HasMultiplePackages
        -            {
        -            my $packages = $self->Package();
        -
        -            foreach my $package (@$packages)
        -                {
        -                if ($package->HasMultipleFiles())
        -                    {
        -                    my $fileElements = $package->File();
        -
        -                    foreach my $fileElement (@$fileElements)
        -                        {  push @files, $fileElement->File();  };
        -                    }
        -                else
        -                    {  push @files, $package->File();  };
        -                };
        -            };
        -
        -
        -        # Determine which language defines it the most.
        -
        -        # Keys are language objects, values are counts.
        -        my %languages;
        -        tie %languages, 'Tie::RefHash';
        -
        -        foreach my $file (@files)
        -            {
        -            my $language = NaturalDocs::Languages->LanguageOf($file);
        -
        -            if (exists $languages{$language})
        -                {  $languages{$language}++;  }
        -            else
        -                {  $languages{$language} = 1;  };
        -            };
        -
        -        my $topCount = 0;
        -        my @topLanguages;
        -
        -        while (my ($language, $count) = each %languages)
        -            {
        -            if ($count > $topCount)
        -                {
        -                $topCount = $count;
        -                @topLanguages = ( $language );
        -                }
        -            elsif ($count == $topCount)
        -                {
        -                push @topLanguages, $language;
        -                };
        -            };
        -
        -        if (scalar @topLanguages == 1)
        -            {  $finalLanguage = $topLanguages[0];  }
        -        else
        -            {
        -            if ($topLanguages[0]->Name() ne 'Text File')
        -                {  $finalLanguage = $topLanguages[0];  }
        -            else
        -                {  $finalLanguage = $topLanguages[1];  };
        -            };
        -        }
        -
        -    else # !hasMultiplePackages && !hasMultipleFiles
        -        {  $finalLanguage = NaturalDocs::Languages->LanguageOf($self->File());  };
        -
        -    my $textSymbol = NaturalDocs::SymbolString->ToText($self->Symbol(), $self->PackageSeparator());
        -    my $ignoredPrefixLength = $finalLanguage->IgnoredPrefixLength($textSymbol, $self->CombinedType());
        -
        -    if ($ignoredPrefixLength)
        -        {
        -        $self->[IGNORED_PREFIX] = substr($textSymbol, 0, $ignoredPrefixLength);
        -        $self->[SORTABLE_SYMBOL] = substr($textSymbol, $ignoredPrefixLength);
        -        }
        -    else
        -        {  $self->[SORTABLE_SYMBOL] = $textSymbol;  };
        -    };
        -
        -
        -
        -###############################################################################
        -#
        -#   Functions: Information Functions
        -#
        -#   Symbol - Returns the <SymbolString> without the package portion.
        -#   Package - If <HasMultiplePackages()> is true, returns an arrayref of <NaturalDocs::SymbolTable::IndexElement> objects.
        -#                  Otherwise returns the package <SymbolString>, or undef if global.
        -#   File - If <HasMultipleFiles()> is true, returns an arrayref of <NaturalDocs::SymbolTable::IndexElement> objects.  Otherwise
        -#           returns the name of the definition file.
        -#   Type - Returns the <TopicType> of the package/symbol/file, if applicable.
        -#   Prototype - Returns the prototype of the package/symbol/file, if applicable.
        -#   Summary - Returns the summary of the package/symbol/file, if applicable.
        -#   CombinedType - Returns the combined <TopicType> of the element.
        -#   PackageSeparator - Returns the combined package separator symbol of the element.
        -#   SortableSymbol - Returns the sortable symbol as a text string.  Only available after calling <MakeSortableSymbol()>.
        -#   IgnoredPrefix - Returns the part of the symbol that was stripped off to make the <SortableSymbol()>, or undef if none.
        -#                          Only available after calling <MakeSortableSymbol()>.
        -#
        -
        -#   Function: HasMultiplePackages
        -#   Returns whether <Packages()> is broken out into more elements.
        -sub HasMultiplePackages
        -    {  return ref($_[0]->[PACKAGE]);  };
        -
        -#   Function: HasMultipleFiles
        -#   Returns whether <File()> is broken out into more elements.
        -sub HasMultipleFiles
        -    {  return ref($_[0]->[FILE]);  };
        -
        -
        -
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -#
        -#   Function: MergeFile
        -#
        -#   Adds another definition of the same package/symbol.  Perhaps the file is different.
        -#
        -#   Parameters:
        -#
        -#       file  - The package/symbol's definition file.
        -#       type  - The package/symbol's <TopicType>.
        -#       prototype  - The package/symbol's protoype if applicable.
        -#       summary  - The package/symbol's summary if applicable.
        -#
        -sub MergeFile #(file, type, prototype, summary)
        -    {
        -    my ($self, $file, $type, $prototype, $summary) = @_;
        -
        -    # If there's only one file...
        -    if (!$self->HasMultipleFiles())
        -        {
        -        # If there's one file and it's the different from the new one...
        -        if ($file ne $self->File())
        -            {
        -            my $selfDefinition = NaturalDocs::SymbolTable::IndexElement->New(undef, undef, $self->File(), $self->Type(),
        -                                                                                                                 $self->Prototype(), $self->Summary(),
        -                                                                                                                 $self->CombinedType(),
        -                                                                                                                 $self->PackageSeparator());
        -            my $newDefinition = NaturalDocs::SymbolTable::IndexElement->New(undef, undef, $file, $type, $prototype,
        -                                                                                                                  $summary);
        -
        -            $self->[FILE] = [ $selfDefinition, $newDefinition ];
        -            $self->[TYPE] = undef;
        -            $self->[PROTOTYPE] = undef;
        -            $self->[SUMMARY] = undef;
        -
        -            if ($newDefinition->Type() ne $self->CombinedType())
        -                {  $self->[COMBINED_TYPE] = ::TOPIC_GENERAL();  };
        -            if ($newDefinition->PackageSeparator() ne $self->PackageSeparator())
        -                {  $self->[PACKAGE_SEPARATOR] = '.';  };
        -            }
        -
        -        # If the file was the same, just ignore the duplicate in the index.
        -        }
        -
        -    # If there's more than one file...
        -    else
        -        {
        -        # See if the new file is one of them.
        -        my $files = $self->File();
        -
        -        foreach my $testElement (@$files)
        -            {
        -            if ($testElement->File() eq $file)
        -                {
        -                # If the new file's already in the index, ignore the duplicate.
        -                return;
        -                };
        -            };
        -
        -        my $newDefinition = NaturalDocs::SymbolTable::IndexElement->New(undef, undef, $file, $type, $prototype,
        -                                                                                                              $summary);
        -        push @{$self->[FILE]}, $newDefinition;
        -
        -        if ($newDefinition->Type() ne $self->CombinedType())
        -            {  $self->[COMBINED_TYPE] = ::TOPIC_GENERAL();  };
        -        if ($newDefinition->PackageSeparator() ne $self->PackageSeparator())
        -            {  $self->[PACKAGE_SEPARATOR] = '.';  };
        -        };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/Reference.pm b/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/Reference.pm
        deleted file mode 100644
        index fd5ef7047..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/Reference.pm
        +++ /dev/null
        @@ -1,274 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::SymbolTable::Reference
        -#
        -###############################################################################
        -#
        -#   A class representing a symbol or a potential symbol.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::SymbolTable::Reference;
        -
        -
        -###############################################################################
        -# Group: Implementation
        -
        -#
        -#   Constants: Members
        -#
        -#   The class is implemented as a blessed arrayref.  The following constants are its members.
        -#
        -#       DEFINITIONS                        - An existence hashref of the <FileNames> that define this reference.
        -#       INTERPRETATIONS                - A hashref of the possible interpretations of this reference.  The keys are the <SymbolStrings>
        -#                                                     and the values are the scores.
        -#       CURRENT_INTERPRETATION  - The interpretation currently used as the reference target.  It will be the interpretation with
        -#                                                     the highest score that is actually defined.  If none are defined, this item will be undef.
        -#
        -
        -# DEPENDENCY: New() depends on the order of these constants.  If they change, New() has to be updated.
        -use constant DEFINITIONS => 0;
        -use constant INTERPRETATIONS => 1;
        -use constant CURRENT_INTERPRETATION => 2;
        -
        -
        -###############################################################################
        -# Group: Modification Functions
        -
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -sub New
        -    {
        -    my $package = shift;
        -
        -    # Let's make it safe, since normally you can pass values to New.  Having them just be ignored would be an obscure error.
        -    if (scalar @_)
        -        {  die "You can't pass values to NaturalDocs::SymbolTable::Reference->New()\n";  };
        -
        -    # DEPENDENCY: This code depends on the order of the member constants.
        -    my $object = [ { }, { }, undef ];
        -    bless $object, $package;
        -
        -    return $object;
        -    };
        -
        -
        -#
        -#   Function: AddDefinition
        -#
        -#   Adds a reference definition.
        -#
        -#   Parameters:
        -#
        -#       file   - The <FileName> that defines the reference.
        -#
        -sub AddDefinition #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    $self->[DEFINITIONS]{$file} = 1;
        -    };
        -
        -
        -#
        -#   Function: DeleteDefinition
        -#
        -#   Removes a reference definition.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName> which has the definition to delete.
        -#
        -sub DeleteDefinition #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    delete $self->[DEFINITIONS]{$file};
        -    };
        -
        -
        -#
        -#   Function: AddInterpretation
        -#
        -#   Adds a symbol that this reference can be interpreted as.
        -#
        -#   Parameters:
        -#
        -#       symbol  - The <SymbolString>.
        -#       score     - The score of this interpretation.
        -#
        -sub AddInterpretation #(symbol, score)
        -    {
        -    my ($self, $symbol, $score) = @_;
        -
        -    $self->[INTERPRETATIONS]{$symbol} = $score;
        -    };
        -
        -
        -#
        -#   Function: DeleteInterpretation
        -#
        -#   Deletes a symbol that this reference can be interpreted as.
        -#
        -#   Parameters:
        -#
        -#       symbol - The <SymbolString> to delete.
        -#
        -sub DeleteInterpretation #(symbol)
        -    {
        -    my ($self, $symbol) = @_;
        -
        -    delete $self->[INTERPRETATIONS]{$symbol};
        -    };
        -
        -
        -#
        -#   Function: DeleteAllInterpretationsButCurrent
        -#
        -#   Deletes all interpretations except for the current one.
        -#
        -sub DeleteAllInterpretationsButCurrent
        -    {
        -    my $self = shift;
        -
        -    if ($self->HasCurrentInterpretation())
        -        {
        -        my $score = $self->CurrentScore();
        -
        -        # Fastest way to clear a hash except for one item?  Make a new hash with just that item.
        -        %{$self->[INTERPRETATIONS]} = ( $self->[CURRENT_INTERPRETATION] => $score );
        -        };
        -    };
        -
        -
        -#
        -#   Function: SetCurrentInterpretation
        -#
        -#   Changes the current interpretation.  The new one must already have been added via <AddInterpretation()>.
        -#
        -#   Parameters:
        -#
        -#       symbol - The <SymbolString>l to make the current interpretation.  Can be set to undef to clear it.
        -#
        -sub SetCurrentInterpretation #(symbol)
        -    {
        -    my ($self, $symbol) = @_;
        -
        -    $self->[CURRENT_INTERPRETATION] = $symbol;
        -    };
        -
        -
        -###############################################################################
        -# Group: Information Functions
        -
        -
        -#
        -#   Function: Definitions
        -#
        -#   Returns an array of all the <FileNames> that define this reference.  If none do, returns an empty array.
        -#
        -sub Definitions
        -    {
        -    return keys %{$_[0]->[DEFINITIONS]};
        -    };
        -
        -
        -#
        -#   Function: IsDefined
        -#
        -#   Returns whether the reference has any definitions or not.
        -#
        -sub IsDefined
        -    {
        -    return scalar keys %{$_[0]->[DEFINITIONS]};
        -    };
        -
        -
        -#
        -#   Function: IsDefinedIn
        -#
        -#   Returns whether the reference is defined in the passed <FileName>.
        -#
        -sub IsDefinedIn #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    return exists $self->[DEFINITIONS]{$file};
        -    };
        -
        -
        -#
        -#   Function: Interpretations
        -#
        -#   Returns an array of all the <SymbolStrings> that this reference can be interpreted as.  If none, returns an empty array.
        -#
        -sub Interpretations
        -    {
        -    return keys %{$_[0]->[INTERPRETATIONS]};
        -    };
        -
        -
        -#
        -#   Function: InterpretationsAndScores
        -#
        -#   Returns a hash of all the <SymbolStrings> that this reference can be interpreted as and their scores.  The keys are the <SymbolStrings>
        -#   and the values are the scores.  If none, returns an empty hash.
        -#
        -sub InterpretationsAndScores
        -    {
        -    return %{$_[0]->[INTERPRETATIONS]};
        -    };
        -
        -
        -#
        -#   Function: HasCurrentInterpretation
        -#
        -#   Returns whether the reference has a current interpretation or not.
        -#
        -sub HasCurrentInterpretation
        -    {
        -    return defined $_[0]->[CURRENT_INTERPRETATION];
        -    };
        -
        -
        -#
        -#   Function: CurrentInterpretation
        -#
        -#   Returns the <SymbolString> of the current interpretation, or undef if none.
        -#
        -sub CurrentInterpretation
        -    {
        -    return $_[0]->[CURRENT_INTERPRETATION];
        -    };
        -
        -
        -#
        -#   Function: CurrentScore
        -#
        -#   Returns the score of the current interpretation, or undef if none.
        -#
        -sub CurrentScore
        -    {
        -    my $self = shift;
        -
        -    if (defined $self->[CURRENT_INTERPRETATION])
        -        {
        -        return $self->[INTERPRETATIONS]{ $self->[CURRENT_INTERPRETATION] };
        -        }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/ReferenceTarget.pm b/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/ReferenceTarget.pm
        deleted file mode 100644
        index 4f9ee407f..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/ReferenceTarget.pm
        +++ /dev/null
        @@ -1,98 +0,0 @@
        -###############################################################################
        -#
        -#   Class: NaturalDocs::SymbolTable::ReferenceTarget
        -#
        -###############################################################################
        -#
        -#   A class for storing information about a reference target.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::SymbolTable::ReferenceTarget;
        -
        -
        -###############################################################################
        -# Group: Implementation
        -
        -#
        -#   Constants: Members
        -#
        -#   The class is implemented as a blessed arrayref.  The following constants are its members.
        -#
        -#       SYMBOL  - The target <SymbolString>.
        -#       FILE        - The <FileName> the target is defined in.
        -#       TYPE       - The target <TopicType>.
        -#       PROTOTYPE - The target's prototype, or undef if none.
        -#       SUMMARY    - The target's summary, or undef if none.
        -#
        -
        -# DEPENDENCY: New() depends on the order of these constants.  If they change, New() has to be updated.
        -use constant SYMBOL => 0;
        -use constant FILE => 1;
        -use constant TYPE => 2;
        -use constant PROTOTYPE => 3;
        -use constant SUMMARY => 4;
        -
        -###############################################################################
        -# Group: Functions
        -
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -#   Parameters:
        -#
        -#       symbol - The target <SymbolString>.
        -#       file       - The <FileName> the target is defined in.
        -#       type     - The <TopicType> of the target symbol.
        -#       prototype - The target's prototype.  Set to undef if not defined or not applicable.
        -#       summary - The target's summary.  Set to undef if not defined or not applicable.
        -#
        -sub New #(symbol, file, type, prototype, summary)
        -    {
        -    # DEPENDENCY: This code depends on the order of the member constants.
        -
        -    my $package = shift;
        -
        -    my $object = [ @_ ];
        -    bless $object, $package;
        -
        -    return $object;
        -    };
        -
        -
        -# Function: Symbol
        -# Returns the target's <SymbolString>.
        -sub Symbol
        -    {  return $_[0]->[SYMBOL];  };
        -
        -# Function: File
        -# Returns the <FileName> the target is defined in.
        -sub File
        -    {  return $_[0]->[FILE];  };
        -
        -# Function: Type
        -# Returns the target's <TopicType>.
        -sub Type
        -    {  return $_[0]->[TYPE];  };
        -
        -# Function: Prototype
        -# Returns the target's prototype, or undef if not defined or not applicable.
        -sub Prototype
        -    {  return $_[0]->[PROTOTYPE];  };
        -
        -# Function: Summary
        -# Returns the target's summary, or undef if not defined or not applicable.
        -sub Summary
        -    {  return $_[0]->[SUMMARY];  };
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/Symbol.pm b/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/Symbol.pm
        deleted file mode 100644
        index 83a7148a3..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/Symbol.pm
        +++ /dev/null
        @@ -1,429 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::SymbolTable::Symbol
        -#
        -###############################################################################
        -#
        -#   A class representing a symbol or a potential symbol.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::SymbolTable::Symbol;
        -
        -
        -###############################################################################
        -# Group: Implementation
        -
        -#
        -#   Constants: Members
        -#
        -#   The class is implemented as a blessed arrayref.  The following constants are its members.
        -#
        -#       DEFINITIONS             - A hashref of all the files which define this symbol.  The keys are the <FileNames>, and the values are
        -#                                         <NaturalDocs::SymbolTable::SymbolDefinition> objects.  If no files define this symbol, this item will
        -#                                          be undef.
        -#       GLOBAL_DEFINITION  - The <FileName> which defines the global version of the symbol, which is what is used if
        -#                                          a file references the symbol but does not have its own definition.  If there are no definitions, this
        -#                                          item will be undef.
        -#       REFERENCES              - A hashref of the references that can be interpreted as this symbol.  This doesn't mean these
        -#                                          references necessarily are.  The keys are the reference strings, and the values are the scores of
        -#                                          the interpretations.  If no references can be interpreted as this symbol, this item will be undef.
        -#
        -use constant DEFINITIONS => 0;
        -use constant GLOBAL_DEFINITION => 1;
        -use constant REFERENCES => 2;
        -
        -
        -###############################################################################
        -# Group: Modification Functions
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -sub New
        -    {
        -    my $package = shift;
        -
        -    # Let's make it safe, since normally you can pass values to New.  Having them just be ignored would be an obscure error.
        -    if (scalar @_)
        -        {  die "You can't pass values to NaturalDocs::SymbolTable::Symbol->New()\n";  };
        -
        -    my $object = [ undef, undef, undef ];
        -    bless $object, $package;
        -
        -    return $object;
        -    };
        -
        -#
        -#   Function: AddDefinition
        -#
        -#   Adds a symbol definition.  If this is the first definition for this symbol, it will become the global definition.  If the definition
        -#   already exists for the file, it will be ignored.
        -#
        -#   Parameters:
        -#
        -#       file   - The <FileName> that defines the symbol.
        -#       type - The <TopicType> of the definition.
        -#       prototype - The prototype of the definition, if applicable.  Undef otherwise.
        -#       summary - The summary for the definition, if applicable.  Undef otherwise.
        -#
        -#   Returns:
        -#
        -#       Whether this provided the first definition for this symbol.
        -#
        -sub AddDefinition #(file, type, prototype, summary)
        -    {
        -    my ($self, $file, $type, $prototype, $summary) = @_;
        -
        -    my $isFirst;
        -
        -    if (!defined $self->[DEFINITIONS])
        -        {
        -        $self->[DEFINITIONS] = { };
        -        $self->[GLOBAL_DEFINITION] = $file;
        -        $isFirst = 1;
        -        };
        -
        -    if (!exists $self->[DEFINITIONS]{$file})
        -        {
        -        $self->[DEFINITIONS]{$file} = NaturalDocs::SymbolTable::SymbolDefinition->New($type, $prototype, $summary);
        -        };
        -
        -    return $isFirst;
        -    };
        -
        -
        -#
        -#   Function: ChangeDefinition
        -#
        -#   Changes the information about an existing definition.
        -#
        -#   Parameters:
        -#
        -#       file   - The <FileName> that defines the symbol.  Must exist.
        -#       type - The new <TopicType> of the definition.
        -#       prototype - The new prototype of the definition, if applicable.  Undef otherwise.
        -#       summary - The new summary of the definition, if applicable.  Undef otherwise.
        -#
        -sub ChangeDefinition #(file, type, prototype, summary)
        -    {
        -    my ($self, $file, $type, $prototype, $summary) = @_;
        -
        -    if (defined $self->[DEFINITIONS] &&
        -        exists $self->[DEFINITIONS]{$file})
        -        {
        -        $self->[DEFINITIONS]{$file}->SetType($type);
        -        $self->[DEFINITIONS]{$file}->SetPrototype($prototype);
        -        $self->[DEFINITIONS]{$file}->SetSummary($summary);
        -        };
        -    };
        -
        -
        -#
        -#   Function: DeleteDefinition
        -#
        -#   Removes a symbol definition.  If the definition served as the global definition, a new one will be selected.
        -#
        -#   Parameters:
        -#
        -#       file - The <FileName> which contains definition to delete.
        -#
        -#   Returns:
        -#
        -#       Whether that was the only definition, and the symbol is now undefined.
        -#
        -sub DeleteDefinition #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    # If there are no definitions...
        -    if (!defined $self->[DEFINITIONS])
        -        {  return undef;  };
        -
        -    delete $self->[DEFINITIONS]{$file};
        -
        -    # If there are no more definitions...
        -    if (!scalar keys %{$self->[DEFINITIONS]})
        -        {
        -        $self->[DEFINITIONS] = undef;
        -
        -        # If definitions was previously defined, and now is empty, we can safely assume that the global definition was just deleted
        -        # without checking it against $file.
        -
        -        $self->[GLOBAL_DEFINITION] = undef;
        -
        -        return 1;
        -        }
        -
        -    # If there are more definitions and the global one was just deleted...
        -    elsif ($self->[GLOBAL_DEFINITION] eq $file)
        -        {
        -        # Which one becomes global is pretty much random.
        -        $self->[GLOBAL_DEFINITION] = (keys %{$self->[DEFINITIONS]})[0];
        -        return undef;
        -        };
        -    };
        -
        -
        -#
        -#   Function: AddReference
        -#
        -#   Adds a reference that can be interpreted as this symbol.  It can be, but not necessarily is.
        -#
        -#   Parameters:
        -#
        -#       referenceString - The string of the reference.
        -#       score                - The score of this interpretation.
        -#
        -sub AddReference #(referenceString, score)
        -    {
        -    my ($self, $referenceString, $score) = @_;
        -
        -    if (!defined $self->[REFERENCES])
        -        {  $self->[REFERENCES] = { };  };
        -
        -    $self->[REFERENCES]{$referenceString} = $score;
        -    };
        -
        -
        -#
        -#   Function: DeleteReference
        -#
        -#   Deletes a reference that can be interpreted as this symbol.
        -#
        -#   Parameters:
        -#
        -#       referenceString - The string of the reference to delete.
        -#
        -sub DeleteReference #(referenceString)
        -    {
        -    my ($self, $referenceString) = @_;
        -
        -    # If there are no definitions...
        -    if (!defined $self->[REFERENCES])
        -        {  return;  };
        -
        -    delete $self->[REFERENCES]{$referenceString};
        -
        -    # If there are no more definitions...
        -    if (!scalar keys %{$self->[REFERENCES]})
        -        {
        -        $self->[REFERENCES] = undef;
        -        };
        -    };
        -
        -
        -#
        -#   Function: DeleteAllReferences
        -#
        -#   Removes all references that can be interpreted as this symbol.
        -#
        -sub DeleteAllReferences
        -    {
        -    $_[0]->[REFERENCES] = undef;
        -    };
        -
        -
        -###############################################################################
        -# Group: Information Functions
        -
        -#
        -#   Function: IsDefined
        -#
        -#   Returns whether the symbol is defined anywhere or not.  If it's not, that means it's just a potential interpretation of a
        -#   reference.
        -#
        -sub IsDefined
        -    {
        -    return defined $_[0]->[GLOBAL_DEFINITION];
        -    };
        -
        -#
        -#   Function: IsDefinedIn
        -#
        -#   Returns whether the symbol is defined in the passed <FileName>.
        -#
        -sub IsDefinedIn #(file)
        -    {
        -    my ($self, $file) = @_;
        -    return ($self->IsDefined() && exists $self->[DEFINITIONS]{$file});
        -    };
        -
        -
        -#
        -#   Function: Definitions
        -#
        -#   Returns an array of all the <FileNames> that define this symbol.  If none do, will return an empty array.
        -#
        -sub Definitions
        -    {
        -    my $self = shift;
        -
        -    if ($self->IsDefined())
        -        {  return keys %{$self->[DEFINITIONS]};  }
        -    else
        -        {  return ( );  };
        -    };
        -
        -
        -#
        -#   Function: GlobalDefinition
        -#
        -#   Returns the <FileName> that contains the global definition of this symbol, or undef if the symbol isn't defined.
        -#
        -sub GlobalDefinition
        -    {
        -    return $_[0]->[GLOBAL_DEFINITION];
        -    };
        -
        -
        -#
        -#   Function: TypeDefinedIn
        -#
        -#   Returns the <TopicType> of the symbol defined in the passed <FileName>, or undef if it's not defined in that file.
        -#
        -sub TypeDefinedIn #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    if ($self->IsDefined())
        -        {  return $self->[DEFINITIONS]{$file}->Type();  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: GlobalType
        -#
        -#   Returns the <TopicType> of the global definition, or undef if the symbol isn't defined.
        -#
        -sub GlobalType
        -    {
        -    my $self = shift;
        -
        -    my $globalDefinition = $self->GlobalDefinition();
        -
        -    if (!defined $globalDefinition)
        -        {  return undef;  }
        -    else
        -        {  return $self->[DEFINITIONS]{$globalDefinition}->Type();  };
        -    };
        -
        -
        -#
        -#   Function: PrototypeDefinedIn
        -#
        -#   Returns the prototype of symbol defined in the passed <FileName>, or undef if it doesn't exist or is not defined in that file.
        -#
        -sub PrototypeDefinedIn #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    if ($self->IsDefined())
        -        {  return $self->[DEFINITIONS]{$file}->Prototype();  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: GlobalPrototype
        -#
        -#   Returns the prototype of the global definition.  Will be undef if it doesn't exist or the symbol isn't defined.
        -#
        -sub GlobalPrototype
        -    {
        -    my $self = shift;
        -
        -    my $globalDefinition = $self->GlobalDefinition();
        -
        -    if (!defined $globalDefinition)
        -        {  return undef;  }
        -    else
        -        {  return $self->[DEFINITIONS]{$globalDefinition}->Prototype();  };
        -    };
        -
        -
        -#
        -#   Function: SummaryDefinedIn
        -#
        -#   Returns the summary of symbol defined in the passed <FileName>, or undef if it doesn't exist or is not defined in that file.
        -#
        -sub SummaryDefinedIn #(file)
        -    {
        -    my ($self, $file) = @_;
        -
        -    if ($self->IsDefined())
        -        {  return $self->[DEFINITIONS]{$file}->Summary();  }
        -    else
        -        {  return undef;  };
        -    };
        -
        -
        -#
        -#   Function: GlobalSummary
        -#
        -#   Returns the summary of the global definition.  Will be undef if it doesn't exist or the symbol isn't defined.
        -#
        -sub GlobalSummary
        -    {
        -    my $self = shift;
        -
        -    my $globalDefinition = $self->GlobalDefinition();
        -
        -    if (!defined $globalDefinition)
        -        {  return undef;  }
        -    else
        -        {  return $self->[DEFINITIONS]{$globalDefinition}->Summary();  };
        -    };
        -
        -
        -#
        -#   Function: HasReferences
        -#
        -#   Returns whether the symbol can be interpreted as any references.
        -#
        -sub HasReferences
        -    {
        -    return defined $_[0]->[REFERENCES];
        -    };
        -
        -#
        -#   Function: References
        -#
        -#   Returns an array of all the reference strings that can be interpreted as this symbol.  If none, will return an empty array.
        -#
        -sub References
        -    {
        -    if (defined $_[0]->[REFERENCES])
        -        {  return keys %{$_[0]->[REFERENCES]};  }
        -    else
        -        {  return ( );  };
        -    };
        -
        -
        -#
        -#   Function: ReferencesAndScores
        -#
        -#   Returns a hash of all the references that can be interpreted as this symbol and their scores.  The keys are the reference
        -#   strings, and the values are the scores.  If none, will return an empty hash.
        -#
        -sub ReferencesAndScores
        -    {
        -    if (defined $_[0]->[REFERENCES])
        -        {  return %{$_[0]->[REFERENCES]};  }
        -    else
        -        {  return ( );  };
        -    };
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/SymbolDefinition.pm b/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/SymbolDefinition.pm
        deleted file mode 100644
        index 9d5746057..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/SymbolTable/SymbolDefinition.pm
        +++ /dev/null
        @@ -1,97 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::SymbolTable::SymbolDefinition
        -#
        -###############################################################################
        -#
        -#   A class representing a symbol definition.  This does not store the definition symbol, class, or file.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::SymbolTable::SymbolDefinition;
        -
        -
        -###############################################################################
        -# Group: Implementation
        -
        -#
        -#   Constants: Members
        -#
        -#   The class is implemented as a blessed arrayref.  The following constants are its members.
        -#
        -#       TYPE  - The symbol <TopicType>.
        -#       PROTOTYPE  - The symbol's prototype, if applicable.  Will be undef otherwise.
        -#       SUMMARY - The symbol's summary, if applicable.  Will be undef otherwise.
        -#
        -use constant TYPE => 0;
        -use constant PROTOTYPE => 1;
        -use constant SUMMARY => 2;
        -# New depends on the order of the constants.
        -
        -
        -###############################################################################
        -# Group: Functions
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -#   Parameters:
        -#
        -#       type - The symbol <TopicType>.
        -#       prototype  - The symbol prototype, if applicable.  Undef otherwise.
        -#       summary - The symbol's summary, if applicable.  Undef otherwise.
        -#
        -sub New #(type, prototype, summary)
        -    {
        -    # This depends on the parameter list being the same as the constant order.
        -
        -    my $package = shift;
        -
        -    my $object = [ @_ ];
        -    bless $object, $package;
        -
        -    return $object;
        -    };
        -
        -
        -#   Function: Type
        -#   Returns the definition's <TopicType>.
        -sub Type
        -    {  return $_[0]->[TYPE];  };
        -
        -# Function: SetType
        -# Changes the <TopicType>.
        -sub SetType #(type)
        -    {  $_[0]->[TYPE] = $_[1];  };
        -
        -#   Function: Prototype
        -#   Returns the definition's prototype, or undef if it doesn't have one.
        -sub Prototype
        -    {  return $_[0]->[PROTOTYPE];  };
        -
        -# Function: SetPrototype
        -# Changes the prototype.
        -sub SetPrototype #(prototype)
        -    {  $_[0]->[PROTOTYPE] = $_[1];  };
        -
        -#   Function: Summary
        -#   Returns the definition's summary, or undef if it doesn't have one.
        -sub Summary
        -    {  return $_[0]->[SUMMARY];  };
        -
        -# Function: SetSummary
        -# Changes the summary.
        -sub SetSummary #(summary)
        -    {  $_[0]->[SUMMARY] = $_[1];  };
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Topics.pm b/vendor/naturaldocs/Modules/NaturalDocs/Topics.pm
        deleted file mode 100644
        index d2668782a..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Topics.pm
        +++ /dev/null
        @@ -1,1320 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Topics
        -#
        -###############################################################################
        -#
        -#   The topic constants and functions to convert them to and from strings used throughout the script.  All constants are exported
        -#   by default.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use Text::Wrap ( );
        -use Tie::RefHash ( );
        -
        -use strict;
        -use integer;
        -
        -use NaturalDocs::Topics::Type;
        -
        -package NaturalDocs::Topics;
        -
        -use base 'Exporter';
        -our @EXPORT = ( 'TOPIC_GENERAL', 'TOPIC_GENERIC', 'TOPIC_GROUP', 'TOPIC_CLASS', 'TOPIC_FILE', 'TOPIC_FUNCTION',
        -                          'TOPIC_VARIABLE', 'TOPIC_PROPERTY', 'TOPIC_TYPE', 'TOPIC_ENUMERATION', 'TOPIC_CONSTANT',
        -                          'TOPIC_INTERFACE', 'TOPIC_EVENT', 'TOPIC_DELEGATE', 'TOPIC_SECTION' );
        -
        -
        -
        -###############################################################################
        -# Group: Types
        -
        -
        -#
        -#   Type: TopicType
        -#
        -#   A string representing a topic type as defined in <Topics.txt>.  It's format should be treated as opaque; use <MakeTopicType()>
        -#   to get them from topic names.  However, they can be compared for equality with string functions.
        -#
        -
        -
        -#
        -#   Constants: Default TopicTypes
        -#
        -#   Exported constants of the default <TopicTypes>, so you don't have to go through <TypeFromName()> every time.
        -#
        -#   TOPIC_GENERAL - The general <TopicType>, which has the special meaning of none in particular.
        -#   TOPIC_GENERIC - Generic <TopicType>.
        -#   TOPIC_GROUP - Group <TopicType>.
        -#   TOPIC_CLASS - Class <TopicType>.
        -#   TOPIC_INTERFACE - Interface <TopicType>.
        -#   TOPIC_FILE - File <TopicType>.
        -#   TOPIC_SECTION - Section <TopicType>.
        -#   TOPIC_FUNCTION - Function <TopicType>.
        -#   TOPIC_VARIABLE - Variable <TopicType>.
        -#   TOPIC_PROPERTY - Property <TopicType>.
        -#   TOPIC_TYPE - Type <TopicType>.
        -#   TOPIC_CONSTANT - Constant <TopicType>.
        -#   TOPIC_ENUMERATION - Enum <TopicType>.
        -#   TOPIC_DELEGATE - Delegate <TopicType>.
        -#   TOPIC_EVENT - Event <TopicType>.
        -#
        -use constant TOPIC_GENERAL => 'general';
        -use constant TOPIC_GENERIC => 'generic';
        -use constant TOPIC_GROUP => 'group';
        -use constant TOPIC_CLASS => 'class';
        -use constant TOPIC_INTERFACE => 'interface';
        -use constant TOPIC_FILE => 'file';
        -use constant TOPIC_SECTION => 'section';
        -use constant TOPIC_FUNCTION => 'function';
        -use constant TOPIC_VARIABLE => 'variable';
        -use constant TOPIC_PROPERTY => 'property';
        -use constant TOPIC_TYPE => 'type';
        -use constant TOPIC_CONSTANT => 'constant';
        -use constant TOPIC_ENUMERATION => 'enumeration';
        -use constant TOPIC_DELEGATE => 'delegate';
        -use constant TOPIC_EVENT => 'event';
        -# Dependency: The values of these constants must match what is generated by MakeTopicType().
        -# Dependency: These types must be added to requiredTypeNames so that they always exist.
        -
        -
        -
        -
        -###############################################################################
        -# Group: Variables
        -
        -
        -#
        -#   handle: FH_TOPICS
        -#
        -#   The file handle used when writing to <Topics.txt>.
        -#
        -
        -
        -#
        -#   hash: types
        -#
        -#   A hashref that maps <TopicTypes> to <NaturalDocs::Topics::Type>s.
        -#
        -my %types;
        -
        -
        -#
        -#   hash: names
        -#
        -#   A hashref that maps various forms of the all-lowercase type names to <TopicTypes>.  All are in the same hash because
        -#   two names that reduce to the same thing it would cause big problems, and we need to catch that.  Keys include
        -#
        -#   - Topic names
        -#   - Plural topic names
        -#   - Alphanumeric-only topic names
        -#   - Alphanumeric-only plural topic names
        -#
        -my %names;
        -
        -
        -#
        -#   hash: keywords
        -#
        -#   A hashref that maps all-lowercase keywords to their <TopicTypes>.  Must not have any of the same keys as
        -#   <pluralKeywords>.
        -#
        -my %keywords;
        -
        -
        -#
        -#   hash: pluralKeywords
        -#
        -#   A hashref that maps all-lowercase plural keywords to their <TopicTypes>.  Must not have any of the same keys as
        -#   <keywords>.
        -#
        -my %pluralKeywords;
        -
        -
        -#
        -#   hash: indexable
        -#
        -#   An existence hash of all the indexable <TopicTypes>.
        -#
        -my %indexable;
        -
        -
        -#
        -#   array: requiredTypeNames
        -#
        -#   An array of the <TopicType> names which are required to be defined in the main file.  Are in the order they should appear
        -#   when reformatting.
        -#
        -my @requiredTypeNames = ( 'Generic', 'Class', 'Interface', 'Section', 'File', 'Group', 'Function', 'Variable', 'Property', 'Type',
        -                                           'Constant', 'Enumeration', 'Event', 'Delegate' );
        -
        -
        -#
        -#   array: legacyTypes
        -#
        -#   An array that converts the legacy topic types, which were numeric constants prior to 1.3, to the current <TopicTypes>.
        -#   The legacy types are used as an index into the array.  Note that this does not support list type values.
        -#
        -my @legacyTypes = ( TOPIC_GENERAL, TOPIC_CLASS, TOPIC_SECTION, TOPIC_FILE, TOPIC_GROUP, TOPIC_FUNCTION,
        -                                TOPIC_VARIABLE, TOPIC_GENERIC, TOPIC_TYPE, TOPIC_CONSTANT, TOPIC_PROPERTY );
        -
        -
        -#
        -#   array: mainTopicNames
        -#
        -#   An array of the <TopicType> names that are defined in the main <Topics.txt>.
        -#
        -my @mainTopicNames;
        -
        -
        -
        -###############################################################################
        -# Group: Files
        -
        -
        -#
        -#   File: Topics.txt
        -#
        -#   The configuration file that defines or overrides the topic definitions for Natural Docs.  One version sits in Natural Docs'
        -#   configuration directory, and another can be in a project directory to add to or override them.
        -#
        -#   > # [comments]
        -#
        -#   Everything after a # symbol is ignored.
        -#
        -#   Except when specifying topic names, everything below is case-insensitive.
        -#
        -#   > Format: [version]
        -#
        -#   Specifies the file format version of the file.
        -#
        -#
        -#   Sections:
        -#
        -#       > Ignore[d] Keyword[s]: [keyword], [keyword] ...
        -#       >    [keyword]
        -#       >    [keyword], [keyword]
        -#       >    ...
        -#
        -#       Ignores the keywords so that they're not recognized as Natural Docs topics anymore.  Can be specified as a list on the same
        -#       line and/or following like a normal Keywords section.
        -#
        -#       > Topic Type: [name]
        -#       > Alter Topic Type: [name]
        -#
        -#       Creates a new topic type or alters an existing one.  The name can only contain <CFChars> and isn't case sensitive, although
        -#       the original case is remembered for presentation.
        -#
        -#       The name General is reserved.  There are a number of default types that must be defined in the main file as well, but those
        -#       are governed by <NaturalDocs::Topics> and are not included here.  The default types can have their keywords or behaviors
        -#       changed, though, either by editing the default file or by overriding them in the user file.
        -#
        -#       Enumeration is a special type.  It is indexed with Types and its definition list members are listed with Constants according
        -#       to the rules in <Languages.txt>.
        -#
        -#
        -#   Topic Type Sections:
        -#
        -#       > Plural: [name]
        -#
        -#       Specifies the plural name of the topic type.  Defaults to the singular name.  Has the same restrictions as the topic type
        -#       name.
        -#
        -#       > Index: [yes|no]
        -#
        -#       Whether the topic type gets an index.  Defaults to yes.
        -#
        -#       > Scope: [normal|start|end|always global]
        -#
        -#       How the topic affects scope.  Defaults to normal.
        -#
        -#       normal - The topic stays within the current scope.
        -#       start - The topic starts a new scope for all the topics beneath it, like class topics.
        -#       end - The topic resets the scope back to global for all the topics beneath it, like section topics.
        -#       always global - The topic is defined as a global symbol, but does not change the scope for any other topics.
        -#
        -#       > Class Hierarchy: [yes|no]
        -#
        -#       Whether the topic is part of the class hierarchy.  Defaults to no.
        -#
        -#       > Page Title if First: [yes|no]
        -#
        -#       Whether the title of this topic becomes the page title if it is the first topic in a file.  Defaults to no.
        -#
        -#       > Break Lists: [yes|no]
        -#
        -#       Whether list topics should be broken into individual topics in the output.  Defaults to no.
        -#
        -#       > Can Group With: [topic type], [topic type], ...
        -#
        -#       The list of <TopicTypes> the topic can possibly be grouped with.
        -#
        -#       > [Add] Keyword[s]:
        -#       >    [keyword]
        -#       >    [keyword], [plural keyword]
        -#       >    ...
        -#
        -#       A list of the topic type's keywords.  Each line after the heading is the keyword and optionally its plural form.  This continues
        -#       until the next line in "keyword: value" format.  "Add" isn't required.
        -#
        -#       - Keywords can only have letters and numbers.  No punctuation or spaces are allowed.
        -#       - Keywords are not case sensitive.
        -#       - Subsequent keyword sections add to the list.  They don't replace it.
        -#       - Keywords can be redefined by other keyword sections.
        -#
        -#
        -#   Revisions:
        -#
        -#       1.3:
        -#
        -#           The initial version of this file.
        -#
        -
        -
        -###############################################################################
        -# Group: File Functions
        -
        -
        -#
        -#   Function: Load
        -#
        -#   Loads both the master and the project version of <Topics.txt>.
        -#
        -sub Load
        -    {
        -    my $self = shift;
        -
        -    # Add the special General topic type.
        -
        -    $types{::TOPIC_GENERAL()} = NaturalDocs::Topics::Type->New('General', 'General', 1, ::SCOPE_NORMAL(), undef);
        -    $names{'general'} = ::TOPIC_GENERAL();
        -    $indexable{::TOPIC_GENERAL()} = 1;
        -    # There are no keywords for the general topic.
        -
        -
        -    $self->LoadFile(1);  # Main
        -
        -    # Dependency: All the default topic types must be checked for existence.
        -
        -    # Check to see if the required types are defined.
        -    foreach my $name (@requiredTypeNames)
        -        {
        -        if (!exists $names{lc($name)})
        -            {  NaturalDocs::ConfigFile->AddError('The ' . $name . ' topic type must be defined in the main topics file.');  };
        -        };
        -
        -    my $errorCount = NaturalDocs::ConfigFile->ErrorCount();
        -
        -    if ($errorCount)
        -        {
        -        NaturalDocs::ConfigFile->PrintErrorsAndAnnotateFile();
        -        NaturalDocs::Error->SoftDeath('There ' . ($errorCount == 1 ? 'is an error' : 'are ' . $errorCount . ' errors')
        -                                                    . ' in ' . NaturalDocs::Project->MainConfigFile('Topics.txt'));
        -        }
        -
        -
        -    $self->LoadFile();  # User
        -
        -    $errorCount = NaturalDocs::ConfigFile->ErrorCount();
        -
        -    if ($errorCount)
        -        {
        -        NaturalDocs::ConfigFile->PrintErrorsAndAnnotateFile();
        -        NaturalDocs::Error->SoftDeath('There ' . ($errorCount == 1 ? 'is an error' : 'are ' . $errorCount . ' errors')
        -                                                    . ' in ' . NaturalDocs::Project->UserConfigFile('Topics.txt'));
        -        }
        -    };
        -
        -
        -#
        -#   Function: LoadFile
        -#
        -#   Loads a particular version of <Topics.txt>.
        -#
        -#   Parameters:
        -#
        -#       isMain - Whether the file is the main file or not.
        -#
        -sub LoadFile #(isMain)
        -    {
        -    my ($self, $isMain) = @_;
        -
        -    my ($file, $status);
        -
        -    if ($isMain)
        -        {
        -        $file = NaturalDocs::Project->MainConfigFile('Topics.txt');
        -        $status = NaturalDocs::Project->MainConfigFileStatus('Topics.txt');
        -        }
        -    else
        -        {
        -        $file = NaturalDocs::Project->UserConfigFile('Topics.txt');
        -        $status = NaturalDocs::Project->UserConfigFileStatus('Topics.txt');
        -        };
        -
        -    my $version;
        -
        -    if ($version = NaturalDocs::ConfigFile->Open($file))
        -        {
        -        # The format hasn't changed since the file was introduced.
        -
        -        if ($status == ::FILE_CHANGED())
        -            {  NaturalDocs::Project->ReparseEverything();  };
        -
        -        my ($topicTypeKeyword, $topicTypeName, $topicType, $topicTypeObject, $inKeywords, $inIgnoredKeywords);
        -
        -        # Keys are topic type objects, values are unparsed strings.
        -        my %canGroupWith;
        -        tie %canGroupWith, 'Tie::RefHash';
        -
        -        while (my ($keyword, $value) = NaturalDocs::ConfigFile->GetLine())
        -            {
        -            if ($keyword)
        -                {
        -                $inKeywords = 0;
        -                $inIgnoredKeywords = 0;
        -                };
        -
        -            if ($keyword eq 'topic type')
        -                {
        -                $topicTypeKeyword = $keyword;
        -                $topicTypeName = $value;
        -
        -                # Resolve conflicts and create the type if necessary.
        -
        -                $topicType = $self->MakeTopicType($topicTypeName);
        -                my $lcTopicTypeName = lc($topicTypeName);
        -
        -                my $lcTopicTypeAName = $lcTopicTypeName;
        -                $lcTopicTypeAName =~ tr/a-z0-9//cd;
        -
        -                if (!NaturalDocs::ConfigFile->HasOnlyCFChars($topicTypeName))
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('Topic names can only have ' . NaturalDocs::ConfigFile->CFCharNames() . '.');
        -                    }
        -                elsif ($topicType eq ::TOPIC_GENERAL())
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('You cannot define a General topic type.');
        -                    }
        -                elsif (defined $types{$topicType} || defined $names{$lcTopicTypeName} || defined $names{$lcTopicTypeAName})
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('Topic type ' . $topicTypeName . ' is already defined or its name is too '
        -                                                                     . 'similar to an existing name.  Use Alter Topic Type if you meant to override '
        -                                                                     . 'its settings.');
        -                    }
        -                else
        -                    {
        -                    $topicTypeObject = NaturalDocs::Topics::Type->New($topicTypeName, $topicTypeName, 1, ::SCOPE_NORMAL(),
        -                                                                                                  0, 0);
        -
        -                    $types{$topicType} = $topicTypeObject;
        -                    $names{$lcTopicTypeName} = $topicType;
        -                    $names{$lcTopicTypeAName} = $topicType;
        -
        -                    $indexable{$topicType} = 1;
        -
        -                    if ($isMain)
        -                        {  push @mainTopicNames, $topicTypeName;  };
        -                    };
        -                }
        -
        -            elsif ($keyword eq 'alter topic type')
        -                {
        -                $topicTypeKeyword = $keyword;
        -                $topicTypeName = $value;
        -
        -                # Resolve conflicts and create the type if necessary.
        -
        -                $topicType = $names{lc($topicTypeName)};
        -
        -                if (!defined $topicType)
        -                    {  NaturalDocs::ConfigFile->AddError('Topic type ' . $topicTypeName . ' doesn\'t exist.');  }
        -                elsif ($topicType eq ::TOPIC_GENERAL())
        -                    {  NaturalDocs::ConfigFile->AddError('You cannot alter the General topic type.');  }
        -                else
        -                    {
        -                    $topicTypeObject = $types{$topicType};
        -                    };
        -                }
        -
        -            elsif ($keyword =~ /^ignored? keywords?$/)
        -                {
        -                $inIgnoredKeywords = 1;
        -
        -                my @ignoredKeywords = split(/ ?, ?/, lc($value));
        -
        -                foreach my $ignoredKeyword (@ignoredKeywords)
        -                    {
        -                    delete $keywords{$ignoredKeyword};
        -                    delete $pluralKeywords{$ignoredKeyword};
        -                    };
        -                }
        -
        -            # We continue even if there are errors in the topic type line so that we can find any other errors in the file as well.  We'd
        -            # rather them all show up at once instead of them showing up one at a time between Natural Docs runs.  So we just ignore
        -            # the settings if $topicTypeObject is undef.
        -
        -
        -            elsif ($keyword eq 'plural')
        -                {
        -                my $pluralName = $value;
        -                my $lcPluralName = lc($pluralName);
        -
        -                my $lcPluralAName = $lcPluralName;
        -                $lcPluralAName =~ tr/a-zA-Z0-9//cd;
        -
        -                if (!NaturalDocs::ConfigFile->HasOnlyCFChars($pluralName))
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('Plural names can only have '
        -                                                                     . NaturalDocs::ConfigFile->CFCharNames() . '.');
        -                    }
        -                elsif ($lcPluralAName eq 'general')
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('You cannot use General as a plural name for ' . $topicTypeName . '.');
        -                    }
        -                elsif ( (defined $names{$lcPluralName} && $names{$lcPluralName} ne $topicType) ||
        -                         (defined $names{$lcPluralAName} && $names{$lcPluralAName} ne $topicType) )
        -                    {
        -                    NaturalDocs::ConfigFile->AddError($topicTypeName . "'s plural name, " . $pluralName
        -                                                                     . ', is already defined or is too similar to an existing name.');
        -                    }
        -
        -                elsif (defined $topicTypeObject)
        -                    {
        -                    $topicTypeObject->SetPluralName($pluralName);
        -
        -                    $names{$lcPluralName} = $topicType;
        -                    $names{$lcPluralAName} = $topicType;
        -                    };
        -                }
        -
        -            elsif ($keyword eq 'index')
        -                {
        -                $value = lc($value);
        -
        -                if ($value eq 'yes')
        -                    {
        -                    if (defined $topicTypeObject)
        -                        {
        -                        $topicTypeObject->SetIndex(1);
        -                        $indexable{$topicType} = 1;
        -                        };
        -                    }
        -                elsif ($value eq 'no')
        -                    {
        -                    if (defined $topicTypeObject)
        -                        {
        -                        $topicTypeObject->SetIndex(0);
        -                        delete $indexable{$topicType};
        -                        };
        -                    }
        -                else
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('Index lines can only be "yes" or "no".');
        -                    };
        -                }
        -
        -            elsif ($keyword eq 'class hierarchy')
        -                {
        -                $value = lc($value);
        -
        -                if ($value eq 'yes')
        -                    {
        -                    if (defined $topicTypeObject)
        -                        {  $topicTypeObject->SetClassHierarchy(1);  };
        -                    }
        -                elsif ($value eq 'no')
        -                    {
        -                    if (defined $topicTypeObject)
        -                        {  $topicTypeObject->SetClassHierarchy(0);  };
        -                    }
        -                else
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('Class Hierarchy lines can only be "yes" or "no".');
        -                    };
        -                }
        -
        -            elsif ($keyword eq 'scope')
        -                {
        -                $value = lc($value);
        -
        -                if ($value eq 'normal')
        -                    {
        -                    if (defined $topicTypeObject)
        -                        {  $topicTypeObject->SetScope(::SCOPE_NORMAL());  };
        -                    }
        -                elsif ($value eq 'start')
        -                    {
        -                    if (defined $topicTypeObject)
        -                        {  $topicTypeObject->SetScope(::SCOPE_START());  };
        -                    }
        -                elsif ($value eq 'end')
        -                    {
        -                    if (defined $topicTypeObject)
        -                        {  $topicTypeObject->SetScope(::SCOPE_END());  };
        -                    }
        -                elsif ($value eq 'always global')
        -                    {
        -                    if (defined $topicTypeObject)
        -                        {  $topicTypeObject->SetScope(::SCOPE_ALWAYS_GLOBAL());  };
        -                    }
        -                else
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('Scope lines can only be "normal", "start", "end", or "always global".');
        -                    };
        -                }
        -
        -            elsif ($keyword eq 'page title if first')
        -                {
        -                $value = lc($value);
        -
        -                if ($value eq 'yes')
        -                    {
        -                    if (defined $topicTypeObject)
        -                        {  $topicTypeObject->SetPageTitleIfFirst(1);  };
        -                    }
        -                elsif ($value eq 'no')
        -                    {
        -                    if (defined $topicTypeObject)
        -                        {  $topicTypeObject->SetPageTitleIfFirst(undef);  };
        -                    }
        -                else
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('Page Title if First lines can only be "yes" or "no".');
        -                    };
        -                }
        -
        -            elsif ($keyword eq 'break lists')
        -                {
        -                $value = lc($value);
        -
        -                if ($value eq 'yes')
        -                    {
        -                    if (defined $topicTypeObject)
        -                        {  $topicTypeObject->SetBreakLists(1);  };
        -                    }
        -                elsif ($value eq 'no')
        -                    {
        -                    if (defined $topicTypeObject)
        -                        {  $topicTypeObject->SetBreakLists(undef);  };
        -                    }
        -                else
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('Break Lists lines can only be "yes" or "no".');
        -                    };
        -                }
        -
        -            elsif ($keyword eq 'can group with')
        -                {
        -                if (defined $topicTypeObject)
        -                    {  $canGroupWith{$topicTypeObject} = lc($value);  };
        -                }
        -
        -            elsif ($keyword =~ /^(?:add )?keywords?$/)
        -                {
        -                $inKeywords = 1;
        -                }
        -
        -            elsif (defined $keyword)
        -                {  NaturalDocs::ConfigFile->AddError($keyword . ' is not a valid keyword.');  }
        -
        -            elsif (!$inKeywords && !$inIgnoredKeywords)
        -                {
        -                NaturalDocs::ConfigFile->AddError('All lines in ' . $topicTypeKeyword . ' sections must begin with a keyword.');
        -                }
        -
        -            else # No keyword but in keyword section.
        -                {
        -                $value = lc($value);
        -
        -                if ($value =~ /^([a-z0-9 ]*[a-z0-9]) ?, ?([a-z0-9 ]+)$/)
        -                    {
        -                    my ($singular, $plural) = ($1, $2);
        -
        -                    if ($inIgnoredKeywords)
        -                        {
        -                        delete $keywords{$singular};
        -                        delete $keywords{$plural};
        -                        delete $pluralKeywords{$singular};
        -                        delete $pluralKeywords{$plural};
        -                        }
        -                    elsif (defined $topicTypeObject)
        -                        {
        -                        $keywords{$singular} = $topicType;
        -                        delete $pluralKeywords{$singular};
        -
        -                        $pluralKeywords{$plural} = $topicType;
        -                        delete $keywords{$plural};
        -                        };
        -                    }
        -                elsif ($value =~ /^[a-z0-9 ]+$/)
        -                    {
        -                    if ($inIgnoredKeywords)
        -                        {
        -                        delete $keywords{$value};
        -                        delete $pluralKeywords{$value};
        -                        }
        -                    elsif (defined $topicType)
        -                        {
        -                        $keywords{$value} = $topicType;
        -                        delete $pluralKeywords{$value};
        -                        };
        -                    }
        -                else
        -                    {
        -                    NaturalDocs::ConfigFile->AddError('Keywords can only have letters, numbers, and spaces.  '
        -                                                                     . 'Plurals must be separated by a comma.');
        -                    };
        -                };
        -            };
        -
        -        NaturalDocs::ConfigFile->Close();
        -
        -
        -        # Parse out the Can Group With lines now that everything's defined.
        -
        -        while (my ($typeObject, $value) = each %canGroupWith)
        -            {
        -            my @values = split(/ ?, ?/, $value);
        -            my @types;
        -
        -            foreach my $value (@values)
        -                {
        -                # We're just going to ignore invalid items.
        -                if (exists $names{$value})
        -                    {  push @types, $names{$value};  };
        -                };
        -
        -            if (scalar @types)
        -                {  $typeObject->SetCanGroupWith(\@types);  };
        -            };
        -        }
        -
        -    else # couldn't open file
        -        {
        -        if ($isMain)
        -            {  die "Couldn't open topics file " . $file . "\n";  }
        -        else
        -            {  NaturalDocs::Project->ReparseEverything();  };
        -        };
        -    };
        -
        -
        -#
        -#   Function: Save
        -#
        -#   Saves the main and user versions of <Topics.txt>.
        -#
        -sub Save
        -    {
        -    my $self = shift;
        -
        -    $self->SaveFile(1); # Main
        -    $self->SaveFile(0); # User
        -    };
        -
        -
        -#
        -#   Function: SaveFile
        -#
        -#   Saves a particular version of <Topics.txt>.
        -#
        -#   Parameters:
        -#
        -#       isMain - Whether the file is the main file or not.
        -#
        -sub SaveFile #(isMain)
        -    {
        -    my ($self, $isMain) = @_;
        -
        -    my $file;
        -
        -    if ($isMain)
        -        {
        -        if (NaturalDocs::Project->MainConfigFileStatus('Topics.txt') == ::FILE_SAME())
        -            {  return;  };
        -        $file = NaturalDocs::Project->MainConfigFile('Topics.txt');
        -        }
        -    else
        -        {
        -        # We have to check the main one two because this lists the topics defined in it.
        -        if (NaturalDocs::Project->UserConfigFileStatus('Topics.txt') == ::FILE_SAME() &&
        -            NaturalDocs::Project->MainConfigFileStatus('Topics.txt') == ::FILE_SAME())
        -            {  return;  };
        -        $file = NaturalDocs::Project->UserConfigFile('Topics.txt');
        -        };
        -
        -
        -    # Array of topic type names in the order they appear in the file.  If Alter Topic Type is used, the name will end with an asterisk.
        -    my @topicTypeOrder;
        -
        -    # Keys are topic type names, values are property hashrefs.  Hashref keys are the property names, values the value.
        -    # For keywords, the key is Keywords and the values are arrayrefs of singular and plural pairs.  If no plural is defined, the entry
        -    # will be undef.
        -    my %properties;
        -
        -    # List of ignored keywords specified as Ignore Keywords: [keyword], [keyword], ...
        -    my @inlineIgnoredKeywords;
        -
        -    # List of ignored keywords specified in [keyword], [plural keyword] lines.  Done in pairs, like for regular keywords.
        -    my @separateIgnoredKeywords;
        -
        -    my $inIgnoredKeywords;
        -
        -    if (NaturalDocs::ConfigFile->Open($file))
        -        {
        -        # We can assume the file is valid.
        -
        -        my ($keyword, $value, $topicTypeName);
        -
        -        while (($keyword, $value) = NaturalDocs::ConfigFile->GetLine())
        -            {
        -            $keyword = lc($keyword);
        -
        -            if ($keyword eq 'topic type' || $keyword eq 'alter topic type')
        -                {
        -                $topicTypeName = $types{ $names{lc($value)} }->Name();
        -
        -                if ($keyword eq 'alter topic type')
        -                    {  $topicTypeName .= '*';  };
        -
        -                push @topicTypeOrder, $topicTypeName;
        -
        -                if (!exists $properties{$topicTypeName})
        -                    {  $properties{$topicTypeName} = { 'keywords' => [ ] };  };
        -                }
        -
        -            elsif ($keyword eq 'plural')
        -                {
        -                $properties{$topicTypeName}->{$keyword} = $value;
        -                }
        -
        -            elsif ($keyword eq 'index' ||
        -                    $keyword eq 'scope' ||
        -                    $keyword eq 'page title if first' ||
        -                    $keyword eq 'class hierarchy' ||
        -                    $keyword eq 'break lists' ||
        -                    $keyword eq 'can group with')
        -                {
        -                $properties{$topicTypeName}->{$keyword} = lc($value);
        -                }
        -
        -            elsif ($keyword =~ /^(?:add )?keywords?$/)
        -                {
        -                $inIgnoredKeywords = 0;
        -                }
        -
        -            elsif ($keyword =~ /^ignored? keywords?$/)
        -                {
        -                $inIgnoredKeywords = 1;
        -                if ($value)
        -                    {  push @inlineIgnoredKeywords, split(/ ?, ?/, $value);  };
        -                }
        -
        -            elsif (!$keyword)
        -                {
        -                my ($singular, $plural) = split(/ ?, ?/, lc($value));
        -
        -                if ($inIgnoredKeywords)
        -                    {  push @separateIgnoredKeywords, $singular, $plural;  }
        -                else
        -                    {  push @{$properties{$topicTypeName}->{'keywords'}}, $singular, $plural;  };
        -                };
        -            };
        -
        -        NaturalDocs::ConfigFile->Close();
        -        };
        -
        -
        -    if (!open(FH_TOPICS, '>' . $file))
        -        {
        -        # The main file may be on a shared volume or some other place the user doesn't have write access to.  Since this is only to
        -        # reformat the file, we can ignore the failure.
        -        if ($isMain)
        -            {  return;  }
        -        else
        -            {  die "Couldn't save " . $file;  };
        -        };
        -
        -    print FH_TOPICS 'Format: ' . NaturalDocs::Settings->TextAppVersion() . "\n\n";
        -
        -    # Remember the 80 character limit.
        -
        -    if ($isMain)
        -        {
        -        print FH_TOPICS
        -        "# This is the main Natural Docs topics file.  If you change anything here, it\n"
        -        . "# will apply to EVERY PROJECT you use Natural Docs on.  If you'd like to\n"
        -        . "# change something for just one project, edit the Topics.txt in its project\n"
        -        . "# directory instead.\n";
        -        }
        -    else
        -        {
        -        print FH_TOPICS
        -        "# This is the Natural Docs topics file for this project.  If you change anything\n"
        -        . "# here, it will apply to THIS PROJECT ONLY.  If you'd like to change something\n"
        -        . "# for all your projects, edit the Topics.txt in Natural Docs' Config directory\n"
        -        . "# instead.\n\n\n";
        -
        -        if (scalar @inlineIgnoredKeywords || scalar @separateIgnoredKeywords)
        -            {
        -            if (scalar @inlineIgnoredKeywords == 1 && !scalar @separateIgnoredKeywords)
        -                {
        -                print FH_TOPICS 'Ignore Keyword: ' . $inlineIgnoredKeywords[0] . "\n";
        -                }
        -            else
        -                {
        -                print FH_TOPICS
        -                'Ignore Keywords: ' . join(', ', @inlineIgnoredKeywords) . "\n";
        -
        -                for (my $i = 0; $i < scalar @separateIgnoredKeywords; $i += 2)
        -                    {
        -                    print FH_TOPICS '   ' . $separateIgnoredKeywords[$i];
        -
        -                    if (defined $separateIgnoredKeywords[$i + 1])
        -                        {  print FH_TOPICS ', ' . $separateIgnoredKeywords[$i + 1];  };
        -
        -                    print FH_TOPICS "\n";
        -                    };
        -                };
        -            }
        -        else
        -            {
        -            print FH_TOPICS
        -            "# If you'd like to prevent keywords from being recognized by Natural Docs, you\n"
        -            . "# can do it like this:\n"
        -            . "# Ignore Keywords: [keyword], [keyword], ...\n"
        -            . "#\n"
        -            . "# Or you can use the list syntax like how they are defined:\n"
        -            . "# Ignore Keywords:\n"
        -            . "#    [keyword]\n"
        -            . "#    [keyword], [plural keyword]\n"
        -            . "#    ...\n";
        -            };
        -        };
        -
        -    print FH_TOPICS # [CFChars]
        -    "\n\n"
        -    . "#-------------------------------------------------------------------------------\n"
        -    . "# SYNTAX:\n"
        -    . "#\n";
        -
        -    if ($isMain)
        -        {
        -        print FH_TOPICS
        -        "# Topic Type: [name]\n"
        -        . "#    Creates a new topic type.  Each type gets its own index and behavior\n"
        -        . "#    settings.  Its name can have letters, numbers, spaces, and these\n"
        -        . "#    charaters: - / . '\n"
        -        . "#\n"
        -        . "#    The Enumeration type is special.  It's indexed with Types but its members\n"
        -        . "#    are indexed with Constants according to the rules in Languages.txt.\n"
        -        . "#\n"
        -        }
        -    else
        -        {
        -        print FH_TOPICS
        -        "# Topic Type: [name]\n"
        -        . "# Alter Topic Type: [name]\n"
        -        . "#    Creates a new topic type or alters one from the main file.  Each type gets\n"
        -        . "#    its own index and behavior settings.  Its name can have letters, numbers,\n"
        -        . "#    spaces, and these charaters: - / . '\n"
        -        . "#\n";
        -        };
        -
        -    print FH_TOPICS
        -    "# Plural: [name]\n"
        -    . "#    Sets the plural name of the topic type, if different.\n"
        -    . "#\n"
        -    . "# Keywords:\n"
        -    . "#    [keyword]\n"
        -    . "#    [keyword], [plural keyword]\n"
        -    . "#    ...\n";
        -
        -    if ($isMain)
        -        {
        -        print FH_TOPICS
        -        "#    Defines a list of keywords for the topic type.  They may only contain\n"
        -        . "#    letters, numbers, and spaces and are not case sensitive.  Plural keywords\n"
        -        . "#    are used for list topics.\n";
        -        }
        -    else
        -        {
        -        print FH_TOPICS
        -        "#    Defines or adds to the list of keywords for the topic type.  They may only\n"
        -        . "#    contain letters, numbers, and spaces and are not case sensitive.  Plural\n"
        -        . "#    keywords are used for list topics.  You can redefine keywords found in the\n"
        -        . "#    main topics file.\n";
        -        }
        -
        -    print FH_TOPICS
        -    "#\n"
        -    . "# Index: [yes|no]\n"
        -    . "#    Whether the topics get their own index.  Defaults to yes.  Everything is\n"
        -    . "#    included in the general index regardless of this setting.\n"
        -    . "#\n"
        -    . "# Scope: [normal|start|end|always global]\n"
        -    . "#    How the topics affects scope.  Defaults to normal.\n"
        -    . "#    normal        - Topics stay within the current scope.\n"
        -    . "#    start         - Topics start a new scope for all the topics beneath it,\n"
        -    . "#                    like class topics.\n"
        -    . "#    end           - Topics reset the scope back to global for all the topics\n"
        -    . "#                    beneath it.\n"
        -    . "#    always global - Topics are defined as global, but do not change the scope\n"
        -    . "#                    for any other topics.\n"
        -    . "#\n"
        -    . "# Class Hierarchy: [yes|no]\n"
        -    . "#    Whether the topics are part of the class hierarchy.  Defaults to no.\n"
        -    . "#\n"
        -    . "# Page Title If First: [yes|no]\n"
        -    . "#    Whether the topic's title becomes the page title if it's the first one in\n"
        -    . "#    a file.  Defaults to no.\n"
        -    . "#\n"
        -    . "# Break Lists: [yes|no]\n"
        -    . "#    Whether list topics should be broken into individual topics in the output.\n"
        -    . "#    Defaults to no.\n"
        -    . "#\n"
        -    . "# Can Group With: [type], [type], ...\n"
        -    . "#    Defines a list of topic types that this one can possibly be grouped with.\n"
        -    . "#    Defaults to none.\n"
        -    . "#-------------------------------------------------------------------------------\n\n";
        -
        -    my $listToPrint;
        -
        -    if ($isMain)
        -        {
        -        print FH_TOPICS
        -        "# The following topics MUST be defined in this file:\n"
        -        . "#\n";
        -        $listToPrint = \@requiredTypeNames;
        -        }
        -    else
        -        {
        -        print FH_TOPICS
        -        "# The following topics are defined in the main file, if you'd like to alter\n"
        -        . "# their behavior or add keywords:\n"
        -        . "#\n";
        -        $listToPrint = \@mainTopicNames;
        -        }
        -
        -    print FH_TOPICS
        -    Text::Wrap::wrap('#    ', '#    ', join(', ', @$listToPrint)) . "\n"
        -    . "\n"
        -    . "# If you add something that you think would be useful to other developers\n"
        -    . "# and should be included in Natural Docs by default, please e-mail it to\n"
        -    . "# topics [at] naturaldocs [dot] org.\n";
        -
        -    # Existence hash.  We do this because we want the required ones to go first by adding them to @topicTypeOrder, but we don't
        -    # want them to appear twice.
        -    my %doneTopicTypes;
        -    my ($altering, $numberOfProperties);
        -
        -    if ($isMain)
        -        {  unshift @topicTypeOrder, @requiredTypeNames;  };
        -
        -    my @propertyOrder = ('Plural', 'Index', 'Scope', 'Class Hierarchy', 'Page Title If First', 'Break Lists');
        -
        -    foreach my $topicType (@topicTypeOrder)
        -        {
        -        if (!exists $doneTopicTypes{$topicType})
        -            {
        -            if (substr($topicType, -1) eq '*')
        -                {
        -                print FH_TOPICS "\n\n"
        -                . 'Alter Topic Type: ' . substr($topicType, 0, -1) . "\n\n";
        -
        -                $altering = 1;
        -                $numberOfProperties = 0;
        -                }
        -            else
        -                {
        -                print FH_TOPICS "\n\n"
        -                . 'Topic Type: ' . $topicType . "\n\n";
        -
        -                $altering = 0;
        -                $numberOfProperties = 0;
        -                };
        -
        -            foreach my $property (@propertyOrder)
        -                {
        -                if (exists $properties{$topicType}->{lc($property)})
        -                    {
        -                    print FH_TOPICS
        -                    '   ' . $property . ': ' . ucfirst( $properties{$topicType}->{lc($property)} ) . "\n";
        -
        -                    $numberOfProperties++;
        -                    };
        -                };
        -
        -            if (exists $properties{$topicType}->{'can group with'})
        -                {
        -                my @typeStrings = split(/ ?, ?/, lc($properties{$topicType}->{'can group with'}));
        -                my @types;
        -
        -                foreach my $typeString (@typeStrings)
        -                    {
        -                    if (exists $names{$typeString})
        -                        {  push @types, $names{$typeString};  };
        -                    };
        -
        -                if (scalar @types)
        -                    {
        -                    for (my $i = 0; $i < scalar @types; $i++)
        -                        {
        -                        my $name = NaturalDocs::Topics->NameOfType($types[$i], 1);
        -
        -                        if ($i == 0)
        -                            {  print FH_TOPICS '   Can Group With: ' . $name;  }
        -                        else
        -                            {  print FH_TOPICS ', ' . $name;  };
        -                        };
        -
        -                    print FH_TOPICS "\n";
        -                    $numberOfProperties++;
        -                    };
        -                };
        -
        -            if (scalar @{$properties{$topicType}->{'keywords'}})
        -                {
        -                if ($numberOfProperties > 1)
        -                    {  print FH_TOPICS "\n";  };
        -
        -                print FH_TOPICS
        -                '   ' . ($altering ? 'Add ' : '') . 'Keywords:' . "\n";
        -
        -                my $keywords = $properties{$topicType}->{'keywords'};
        -
        -                for (my $i = 0; $i < scalar @$keywords; $i += 2)
        -                    {
        -                    print FH_TOPICS '      ' . $keywords->[$i];
        -
        -                    if (defined $keywords->[$i + 1])
        -                        {  print FH_TOPICS ', ' . $keywords->[$i + 1];  };
        -
        -                    print FH_TOPICS "\n";
        -                    };
        -                };
        -
        -            $doneTopicTypes{$topicType} = 1;
        -            };
        -        };
        -
        -    close(FH_TOPICS);
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Functions
        -
        -
        -#
        -#   Function: KeywordInfo
        -#
        -#   Returns information about a topic keyword.
        -#
        -#   Parameters:
        -#
        -#       keyword - The keyword, which may be plural.
        -#
        -#   Returns:
        -#
        -#       The array ( topicType, info, isPlural ), or an empty array if the keyword doesn't exist.
        -#
        -#       topicType - The <TopicType> of the keyword.
        -#       info - The <NaturalDocs::Topics::Type> of its type.
        -#       isPlural - Whether the keyword was plural or not.
        -#
        -sub KeywordInfo #(keyword)
        -    {
        -    my ($self, $keyword) = @_;
        -
        -    $keyword = lc($keyword);
        -
        -    my $type = $keywords{$keyword};
        -
        -    if (defined $type)
        -        {  return ( $type, $types{$type}, undef );  };
        -
        -    $type = $pluralKeywords{$keyword};
        -
        -    if (defined $type)
        -        {  return ( $type, $types{$type}, 1 );  };
        -
        -    return ( );
        -    };
        -
        -
        -#
        -#   Function: NameInfo
        -#
        -#   Returns information about a topic name.
        -#
        -#   Parameters:
        -#
        -#      name - The topic type name, which can be plural and/or alphanumeric only.
        -#
        -#   Returns:
        -#
        -#       The array ( topicType, info ), or an empty array if the name doesn't exist.  Note that unlike <KeywordInfo()>, this
        -#       does *not* tell you whether the name is plural or not.
        -#
        -#       topicType - The <TopicType> of the name.
        -#       info - The <NaturalDocs::Topics::Type> of the type.
        -#
        -sub NameInfo #(name)
        -    {
        -    my ($self, $name) = @_;
        -
        -    my $type = $names{lc($name)};
        -
        -    if (defined $type)
        -        {  return ( $type, $types{$type} );  }
        -    else
        -        {  return ( );  };
        -    };
        -
        -
        -#
        -#   Function: TypeInfo
        -#
        -#   Returns information about a <TopicType>.
        -#
        -#   Parameters:
        -#
        -#      type - The <TopicType>.
        -#
        -#   Returns:
        -#
        -#       The <NaturalDocs::Topics::Type> of the type, or undef if it didn't exist.
        -#
        -sub TypeInfo #(type)
        -    {
        -    my ($self, $type) = @_;
        -    return $types{$type};
        -    };
        -
        -
        -#
        -#   Function: NameOfType
        -#
        -#   Returns the name of the passed <TopicType>, or undef if it doesn't exist.
        -#
        -#   Parameters:
        -#
        -#       topicType - The <TopicType>.
        -#       plural - Whether to return the plural instead of the singular.
        -#       alphanumericOnly - Whether to strips everything but alphanumeric characters out.  Case isn't modified.
        -#
        -#   Returns:
        -#
        -#       The topic type name, according to what was specified in the parameters, or undef if it doesn't exist.
        -#
        -sub NameOfType #(topicType, plural, alphanumericOnly)
        -    {
        -    my ($self, $topicType, $plural, $alphanumericOnly) = @_;
        -
        -    my $topicObject = $types{$topicType};
        -
        -    if (!defined $topicObject)
        -        {  return undef;  };
        -
        -    my $topicName = ($plural ? $topicObject->PluralName() : $topicObject->Name());
        -
        -    if ($alphanumericOnly)
        -        {  $topicName =~ tr/a-zA-Z0-9//cd;  };
        -
        -    return $topicName;
        -    };
        -
        -
        -#
        -#   Function: TypeFromName
        -#
        -#   Returns a <TopicType> for the passed topic name.
        -#
        -#   Parameters:
        -#
        -#       topicName - The name of the topic, which can be plural and/or alphanumeric only.
        -#
        -#   Returns:
        -#
        -#       The <TopicType>.  It does not specify whether the name was plural or not.
        -#
        -sub TypeFromName #(topicName)
        -    {
        -    my ($self, $topicName) = @_;
        -
        -    return $names{lc($topicName)};
        -    };
        -
        -
        -#
        -#   Function: IsValidType
        -#
        -#   Returns whether the passed <TopicType> is defined.
        -#
        -sub IsValidType #(type)
        -    {
        -    my ($self, $type) = @_;
        -    return exists $types{$type};
        -    };
        -
        -
        -#
        -#   Function: TypeFromLegacy
        -#
        -#   Returns a <TopicType> for the passed legacy topic type integer.  <TopicTypes> were changed from integer constants to
        -#   strings in 1.3.
        -#
        -sub TypeFromLegacy #(legacyInt)
        -    {
        -    my ($self, $int) = @_;
        -    return $legacyTypes[$int];
        -    };
        -
        -
        -#
        -#   Function: AllIndexableTypes
        -#
        -#   Returns an array of all possible indexable <TopicTypes>.
        -#
        -sub AllIndexableTypes
        -    {
        -    my ($self) = @_;
        -    return keys %indexable;
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -
        -
        -#
        -#   Function: MakeTopicType
        -#
        -#   Returns a <TopicType> for the passed topic name.  It does not check to see if it exists already.
        -#
        -#   Parameters:
        -#
        -sub MakeTopicType #(topicName)
        -    {
        -    my ($self, $topicName) = @_;
        -
        -    # Dependency: The values of the default topic type constants must match what is generated here.
        -
        -    # Turn everything to lowercase and strip non-alphanumeric characters.
        -    $topicName = lc($topicName);
        -    $topicName =~ tr/a-z0-9//cd;
        -
        -    return $topicName;
        -    };
        -
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Topics/Type.pm b/vendor/naturaldocs/Modules/NaturalDocs/Topics/Type.pm
        deleted file mode 100644
        index 2ed959e9e..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Topics/Type.pm
        +++ /dev/null
        @@ -1,152 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Topics::Type
        -#
        -###############################################################################
        -#
        -#   A class storing information about a <TopicType>.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -
        -package NaturalDocs::Topics::Type;
        -
        -use NaturalDocs::DefineMembers 'NAME',                         'Name()',
        -                                                 'PLURAL_NAME',             'PluralName()',      'SetPluralName()',
        -                                                 'INDEX',                        'Index()',              'SetIndex()',
        -                                                 'SCOPE',                       'Scope()',              'SetScope()',
        -                                                 'PAGE_TITLE_IF_FIRST', 'PageTitleIfFirst()', 'SetPageTitleIfFirst()',
        -                                                 'BREAK_LISTS',             'BreakLists()',        'SetBreakLists()',
        -                                                 'CLASS_HIERARCHY',    'ClassHierarchy()',  'SetClassHierarchy()',
        -                                                 'CAN_GROUP_WITH';
        -
        -# Dependency: New() depends on the order of these and that there are no parent classes.
        -
        -use base 'Exporter';
        -our @EXPORT = ('SCOPE_NORMAL', 'SCOPE_START', 'SCOPE_END', 'SCOPE_ALWAYS_GLOBAL');
        -
        -#
        -#   Constants: Members
        -#
        -#   The object is implemented as a blessed arrayref, with the following constants as its indexes.
        -#
        -#   NAME - The topic's name.
        -#   PLURAL_NAME - The topic's plural name.
        -#   INDEX - Whether the topic is indexed.
        -#   SCOPE - The topic's <ScopeType>.
        -#   PAGE_TITLE_IF_FIRST - Whether the topic becomes the page title if it's first in a file.
        -#   BREAK_LISTS - Whether list topics should be broken into individual topics in the output.
        -#   CLASS_HIERARCHY - Whether the topic is part of the class hierarchy.
        -#   CAN_GROUP_WITH - The existence hashref of <TopicTypes> the type can be grouped with.
        -#
        -
        -
        -
        -###############################################################################
        -# Group: Types
        -
        -
        -#
        -#   Constants: ScopeType
        -#
        -#   The possible values for <Scope()>.
        -#
        -#   SCOPE_NORMAL - The topic stays in the current scope without affecting it.
        -#   SCOPE_START - The topic starts a scope.
        -#   SCOPE_END - The topic ends a scope, returning it to global.
        -#   SCOPE_ALWAYS_GLOBAL - The topic is always global, but it doesn't affect the current scope.
        -#
        -use constant SCOPE_NORMAL => 1;
        -use constant SCOPE_START => 2;
        -use constant SCOPE_END => 3;
        -use constant SCOPE_ALWAYS_GLOBAL => 4;
        -
        -
        -
        -###############################################################################
        -# Group: Functions
        -
        -
        -#
        -#   Function: New
        -#
        -#   Creates and returns a new object.
        -#
        -#   Parameters:
        -#
        -#       name - The topic name.
        -#       pluralName - The topic's plural name.
        -#       index - Whether the topic is indexed.
        -#       scope - The topic's <ScopeType>.
        -#       pageTitleIfFirst - Whether the topic becomes the page title if it's the first one in a file.
        -#       breakLists - Whether list topics should be broken into individual topics in the output.
        -#
        -sub New #(name, pluralName, index, scope, pageTitleIfFirst, breakLists)
        -    {
        -    my ($self, @params) = @_;
        -
        -    # Dependency: Depends on the parameter order matching the member order and that there are no parent classes.
        -
        -    my $object = [ @params ];
        -    bless $object, $self;
        -
        -    return $object;
        -    };
        -
        -
        -#
        -#   Functions: Accessors
        -#
        -#   Name - Returns the topic name.
        -#   PluralName - Returns the topic's plural name.
        -#   SetPluralName - Replaces the topic's plural name.
        -#   Index - Whether the topic is indexed.
        -#   SetIndex - Sets whether the topic is indexed.
        -#   Scope - Returns the topic's <ScopeType>.
        -#   SetScope - Replaces the topic's <ScopeType>.
        -#   PageTitleIfFirst - Returns whether the topic becomes the page title if it's first in the file.
        -#   SetPageTitleIfFirst - Sets whether the topic becomes the page title if it's first in the file.
        -#   BreakLists - Returns whether list topics should be broken into individual topics in the output.
        -#   SetBreakLists - Sets whether list topics should be broken into individual topics in the output.
        -#   ClassHierarchy - Returns whether the topic is part of the class hierarchy.
        -#   SetClassHierarchy - Sets whether the topic is part of the class hierarchy.
        -#
        -
        -
        -#
        -#   Function: CanGroupWith
        -#
        -#   Returns whether the type can be grouped with the passed <TopicType>.
        -#
        -sub CanGroupWith #(TopicType type) -> bool
        -    {
        -    my ($self, $type) = @_;
        -    return ( defined $self->[CAN_GROUP_WITH] && exists $self->[CAN_GROUP_WITH]->{$type} );
        -    };
        -
        -
        -#
        -#   Function: SetCanGroupWith
        -#
        -#   Sets the list of <TopicTypes> the type can be grouped with.
        -#
        -sub SetCanGroupWith #(TopicType[] types)
        -    {
        -    my ($self, $types) = @_;
        -
        -    $self->[CAN_GROUP_WITH] = { };
        -
        -    foreach my $type (@$types)
        -        {  $self->[CAN_GROUP_WITH]->{$type} = 1;  };
        -    };
        -
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/Modules/NaturalDocs/Version.pm b/vendor/naturaldocs/Modules/NaturalDocs/Version.pm
        deleted file mode 100644
        index 27a22ecb8..000000000
        --- a/vendor/naturaldocs/Modules/NaturalDocs/Version.pm
        +++ /dev/null
        @@ -1,361 +0,0 @@
        -###############################################################################
        -#
        -#   Package: NaturalDocs::Version
        -#
        -###############################################################################
        -#
        -#   A package for handling version information.  What?  That's right.  Although it should be easy and obvious, version numbers
        -#   need to be dealt with in a variety of formats, plus there's compatibility with older releases which handled it differently.  I
        -#   wanted to centralize the code after it started getting complicated.  So there ya go.
        -#
        -###############################################################################
        -
        -# This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
        -# Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
        -# Refer to License.txt for the complete details
        -
        -use strict;
        -use integer;
        -
        -package NaturalDocs::Version;
        -
        -
        -###############################################################################
        -# Group: Functions
        -
        -
        -#
        -#   Function: ToString
        -#
        -#   Converts a <VersionInt> to a string.
        -#
        -sub ToString #(VersionInt version) => string
        -    {
        -    my ($self, $version) = @_;
        -
        -    my ($major, $minor, $month, $day, $year) = $self->ToValues($version);
        -
        -    if ($minor % 10 == 0)
        -        {  $minor /= 10;  };
        -
        -    if ($day)
        -        {  return sprintf('Development Release %02d-%02d-%d (%d.%d base)', $month, $day, $year, $major, $minor);  }
        -    else
        -        {  return $major . '.' . $minor;  };
        -    };
        -
        -
        -#
        -#   Function: FromString
        -#
        -#   Converts a version string to a <VersionInt>.
        -#
        -sub FromString #(string string) => VersionInt
        -    {
        -    my ($self, $string) = @_;
        -
        -    if ($string eq '1')
        -        {
        -        return $self->FromValues(0, 91, 0, 0, 0);  # 0.91
        -        }
        -    else
        -        {
        -        my ($major, $minor, $month, $day, $year);
        -
        -        if ($string =~ /^(\d{1,2})\.(\d{1,2})$/)
        -            {
        -            ($major, $minor) = ($1, $2);
        -            ($month, $day, $year) = (0, 0, 0);
        -            }
        -        elsif ($string =~ /^Development Release (\d{1,2})-(\d{1,2})-(\d\d\d\d) \((\d{1,2})\.(\d{1,2}) base\)$/)
        -            {
        -            ($month, $day, $year, $major, $minor) = ($1, $2, $3, $4, $5);
        -
        -            # We have to do sanity checking because these can come from user-editable text files.  The version numbers should
        -            # already be constrained simply by being forced to have only two digits.
        -
        -            if ($month > 12 || $month < 1 || $day > 31 || $day < 1 || $year > 2255 || $year < 2000)
        -                {  die 'The version string ' . $string . " doesn't have a valid date.\n";  };
        -            }
        -        else
        -            {
        -            die 'The version string ' . $string . " isn't in a recognized format.\n";
        -            };
        -
        -        if (length $minor == 1)
        -            {  $minor *= 10;  };
        -
        -        return $self->FromValues($major, $minor, $month, $day, $year);
        -        };
        -    };
        -
        -
        -#
        -#   Function: ToTextFile
        -#
        -#   Writes a <VersionInt> to a text file.
        -#
        -#   Parameters:
        -#
        -#       fileHandle - The handle of the file to write it to.  It should be at the correct location.
        -#       version - The <VersionInt> to write.
        -#
        -sub ToTextFile #(handle fileHandle, VersionInt version)
        -    {
        -    my ($self, $fileHandle, $version) = @_;
        -
        -    print $fileHandle $self->ToString($version) . "\n";
        -    };
        -
        -
        -#
        -#   Function: ToBinaryFile
        -#
        -#   Writes a <VersionInt> to a binary file.
        -#
        -#   Parameters:
        -#
        -#       fileHandle - The handle of the file to write it to.  It should be at the correct location.
        -#       version - The <VersionInt> to write.
        -#
        -sub ToBinaryFile #(handle fileHandle, VersionInt version)
        -    {
        -    my ($self, $fileHandle, $version) = @_;
        -
        -    my ($major, $minor, $month, $day, $year) = $self->ToValues($version);
        -
        -    # 1.35 development releases are encoded as 1.36.  Everything else is literal.
        -    if ($day && $major == 1 && $minor == 35)
        -        {  $minor = 36;  };
        -
        -    print $fileHandle pack('CC', $major, $minor);
        -
        -    # Date fields didn't exist with 1.35 stable and earlier.  1.35 development releases are encoded as 1.36, so this works.
        -    if ($major > 1 || ($major == 1 && $minor > 35))
        -        {
        -        if ($day)
        -            {  $year -= 2000;  };
        -
        -        print $fileHandle pack('CCC', $month, $day, $year);
        -        };
        -    };
        -
        -
        -#
        -#   Function: FromBinaryFile
        -#
        -#   Retrieves a <VersionInt> from a binary file.
        -#
        -#   Parameters:
        -#
        -#       fileHandle - The handle of the file to read it from.  It should be at the correct location.
        -#
        -#   Returns:
        -#
        -#       The <VersionInt>.
        -#
        -sub FromBinaryFile #(handle fileHandle) => VersionInt
        -    {
        -    my ($self, $fileHandle) = @_;
        -
        -    my ($major, $minor, $month, $day, $year);
        -
        -    my $raw;
        -    read($fileHandle, $raw, 2);
        -
        -    ($major, $minor) = unpack('CC', $raw);
        -
        -    # 1.35 stable is the last release without the date fields.  1.35 development releases are encoded as 1.36, so this works.
        -    if ($major > 1 || ($major == 1 && $minor > 35))
        -        {
        -        read($fileHandle, $raw, 3);
        -        ($month, $day, $year) = unpack('CCC', $raw);
        -
        -        if ($day)
        -            {  $year += 2000;  };
        -        }
        -    else
        -        {  ($month, $day, $year) = (0, 0, 0);  };
        -
        -    # Fix the 1.35 development release special encoding.
        -    if ($major == 1 && $minor == 36)
        -        {  $minor = 35;  };
        -
        -
        -    return $self->FromValues($major, $minor, $month, $day, $year);
        -    };
        -
        -
        -#
        -#   Function: ToValues
        -#
        -#   Converts a <VersionInt> to the array ( major, minor, month, day, year ).  The minor version will be in two digit form, so x.2
        -#   will return 20.  The date fields will be zero for stable releases.
        -#
        -sub ToValues #(VersionInt version) => ( int, int, int, int, int )
        -    {
        -    my ($self, $version) = @_;
        -
        -    my $major = ($version & 0x00003F80) >> 7;
        -    my $minor = ($version & 0x0000007F);
        -    my $month = ($version & 0x00780000) >> 19;
        -    my $day = ($version & 0x0007C000) >> 14;
        -    my $year = ($version & 0x7F800000) >> 23;
        -
        -    if ($year)
        -        {  $year += 2000;  };
        -
        -    return ( $major, $minor, $month, $day, $year );
        -    };
        -
        -
        -#
        -#   Function: FromValues
        -#
        -#   Returns a <VersionInt> created from the passed values.
        -#
        -#   Parameters:
        -#
        -#       major - The major version number.  For development releases, it should be the stable version it's based off of.
        -#       minor - The minor version number.  It should always be two digits, so x.2 should pass 20.  For development
        -#                  releases, it should be the stable version it's based off of.
        -#       month - The numeric month of the development release.  For stable releases it should be zero.
        -#       day - The day of the development release.  For stable releases it should be zero.
        -#       year - The year of the development release.  For stable releases it should be zero.
        -#
        -#   Returns:
        -#
        -#       The <VersionInt>.
        -#
        -sub FromValues #(int major, int minor, int month, int day, int year) => VersionInt
        -    {
        -    my ($self, $major, $minor, $month, $day, $year) = @_;
        -
        -    if ($day)
        -        {  $year -= 2000;  };
        -
        -    return ($major << 7) + ($minor) + ($month << 19) + ($day << 14) + ($year << 23);
        -    };
        -
        -
        -#
        -#   Function: CheckFileFormat
        -#
        -#   Checks if a file's format is compatible with the current release.
        -#
        -#   - If the application is a development release or the file is from one, this only returns true if they are from the exact same
        -#     development release.
        -#   - If neither of them are development releases, this only returns true if the file is from a release between the minimum specified
        -#     and the current version.  If there's no minimum it just checks that it's below the current version.
        -#
        -#   Parameters:
        -#
        -#       fileVersion - The <VersionInt> of the file format.
        -#       minimumVersion - The minimum <VersionInt> required of the file format.  May be undef.
        -#
        -#   Returns:
        -#
        -#       Whether the file's format is compatible per the above rules.
        -#
        -sub CheckFileFormat #(VersionInt fileVersion, optional VersionInt minimumVersion) => bool
        -    {
        -    my ($self, $fileVersion, $minimumVersion) = @_;
        -
        -    my $appVersion = NaturalDocs::Settings->AppVersion();
        -
        -    if ($self->IsDevelopmentRelease($appVersion) || $self->IsDevelopmentRelease($fileVersion))
        -        {  return ($appVersion == $fileVersion);  }
        -    elsif ($minimumVersion && $fileVersion < $minimumVersion)
        -        {  return 0;  }
        -    else
        -        {  return ($fileVersion <= $appVersion);  };
        -    };
        -
        -
        -#
        -#   Function: IsDevelopmentRelease
        -#
        -#   Returns whether the passed <VersionInt> is for a development release.
        -#
        -sub IsDevelopmentRelease #(VersionInt version) => bool
        -    {
        -    my ($self, $version) = @_;
        -
        -    # Return if any of the date fields are set.
        -    return ($version & 0x7FFFC000);
        -    };
        -
        -
        -
        -###############################################################################
        -# Group: Implementation
        -
        -#
        -#   About: String Format
        -#
        -#   Full Releases:
        -#
        -#       Full releases are in the common major.minor format.  Either part can be up to two digits.  The minor version is interpreted
        -#       as decimal places, so 1.3 > 1.22.  There are no leading or trailing zeroes.
        -#
        -#   Development Releases:
        -#
        -#       Development releases are in the format "Development Release mm-dd-yyyy (vv.vv base)" where vv.vv is the version
        -#       number of the full release it's based off of.  The month and day will have leading zeroes where applicable.  Example:
        -#       "Development Release 07-09-2006 (1.35 base)".
        -#
        -#   0.91 and Earlier:
        -#
        -#       Text files from releases prior to 0.95 had a separate file format version number that was used instead of the application
        -#       version.  These were never changed between 0.85 and 0.91, so they are simply "1".  Text version numbers that are "1"
        -#       instead of "1.0" will be interpreted as 0.91.
        -#
        -
        -#
        -#   About: Integer Format
        -#
        -#   <VersionInts> are 32-bit values with the bit distribution below.
        -#
        -#   > s yyyyyyyy mmmm ddddd vvvvvvv xxxxxxx
        -#   > [syyy|yyyy] [ymmm|mddd] [ddvv|vvvv] [vxxx|xxxx]
        -#
        -#   s - The sign bit.  Always zero, so it's always interpreted as positive.
        -#   y - The year bits if it's a development release, zero otherwise.  2000 is added to the value, so the range is from 2000 to 2255.
        -#   m - The month bits if it's a development release, zero otherwise.
        -#   d - The day bits if it's a development release, zero otherwise.
        -#   v - The major version bits.  For development releases, it's the last stable version it was based off of.
        -#   x - The minor version bits.  It's always stored as two decimals, so x.2 would store 20 here.  For development releases, it's the
        -#        last stable version it was based off of.
        -#
        -#   It's stored with the development release date at a higher significance than the version because we want a stable release to
        -#   always treat a development release as higher than itself, and thus not attempt to read any of the data files.  I'm not tracking
        -#   data file formats at the development release level.
        -#
        -
        -#
        -#   About: Binary File Format
        -#
        -#   Current:
        -#
        -#       Five 8-bit unsigned values, appearing major, minor, month, day, year.  Minor is always stored with two digits, so x.2 would
        -#       store 20.  Year is stored minus 2000, so 2006 is stored 6.  Stable releases store zero for all the date fields.
        -#
        -#   1.35 Development Releases:
        -#
        -#       1.35-based development releases are stored the same as current releases, but with 1.36 as the version number.  This is
        -#       done so previous versions of Natural Docs that didn't include the date fields would still know it's a higher version.  There is
        -#       no actual 1.36 release.
        -#
        -#   1.35 and Earlier:
        -#
        -#       Two 8-bit unsigned values, appearing major then minor.  Minor is always stored with two digits, so x.2 would store 20.
        -#
        -
        -#
        -#   About: Text File Format
        -#
        -#   In text files, versions are the <String Format> followed by a native line break.
        -#
        -
        -
        -1;
        diff --git a/vendor/naturaldocs/NaturalDocs b/vendor/naturaldocs/NaturalDocs
        deleted file mode 100755
        index 1d523d6bf..000000000
        --- a/vendor/naturaldocs/NaturalDocs
        +++ /dev/null
        @@ -1,367 +0,0 @@
        -#!/usr/bin/perl
        -
        -=begin nd
        -
        -    Script: NaturalDocs
        -    ___________________________________________________________________________
        -
        -    Version 1.51
        -
        -    Copyright © 2003-2010 Greg Valure
        -
        -    http://www.naturaldocs.org
        -
        -	Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL).  Refer to the <License> for the
        -	complete details.
        -
        -
        -    Topic: Code Conventions
        -
        -        - Every package function is called with an arrow operator.  It's needed for inheritance in some places, and consistency
        -         when it's not.
        -
        -        - No constant will ever be zero or undef.  Those are reserved so any piece of code can allow a "none of the above" option
        -         and not worry about conflicts with an existing value.
        -
        -        - Existence hashes are hashes where the value doesn't matter.  It acts more as a set, where the existence of the key is
        -         the significant part.
        -
        -
        -    Topic: File Format Conventions
        -
        -        - All integers appear in big-endian format.  So a UInt16 should be handled with a 'n' in pack and unpack, not with a 'S'.
        -
        -        - AString16's are a big-endian UInt16 followed by that many ASCII characters.  A null-terminator is not stored.
        -
        -        - If a higher-level type is described in a file format, that means the loading and saving format is handled by that package.
        -         For example, if you see <SymbolString> in the format, that means <NaturalDocs::SymbolString->ToBinaryFile()> and
        -         <NaturalDocs::SymbolString->FromBinaryFile()> are used to manipulate it, and the underlying format should be treated
        -         as opaque.
        -
        -=cut
        -
        -
        -use strict;
        -use integer;
        -
        -use 5.008;  # When :encoding modifiers were allowed with file access.
        -
        -use English '-no_match_vars';
        -
        -use FindBin;
        -use lib "$FindBin::RealBin/Modules";
        -
        -sub INIT
        -    {
        -    # This function is just here so that when I start the debugger, it doesn't open a new file.  Normally it would jump to an INIT
        -    # function in some other file since that's the first piece of code to execute.
        -    };
        -
        -
        -use NaturalDocs::Constants;
        -use NaturalDocs::Version;
        -use NaturalDocs::File;
        -use NaturalDocs::Error;
        -
        -use NaturalDocs::LineReader;
        -use NaturalDocs::ConfigFile;
        -use NaturalDocs::BinaryFile;
        -use NaturalDocs::StatusMessage;
        -use NaturalDocs::SymbolString;
        -use NaturalDocs::ReferenceString;
        -use NaturalDocs::NDMarkup;
        -
        -use NaturalDocs::Settings;
        -use NaturalDocs::Topics;
        -use NaturalDocs::Languages;
        -use NaturalDocs::Project;
        -use NaturalDocs::Menu;
        -use NaturalDocs::SymbolTable;
        -use NaturalDocs::ClassHierarchy;
        -use NaturalDocs::SourceDB;
        -use NaturalDocs::ImageReferenceTable;
        -use NaturalDocs::Parser;
        -use NaturalDocs::Builder;
        -
        -
        -
        -###############################################################################
        -#
        -#   Group: Basic Types
        -#
        -#   Types used throughout the program.  As Perl is a weakly-typed language unless you box things into objects, these types are
        -#   for documentation purposes and are not enforced.
        -#
        -#
        -#   Type: FileName
        -#
        -#   A string representing the absolute, platform-dependent path to a file.  Relative file paths are no longer in use anywhere in the
        -#   program.  All path manipulation should be done through <NaturalDocs::File>.
        -#
        -#
        -#   Type: VersionInt
        -#
        -#   A comparable integer representing a version number.  Converting them to and from text and binary should be handled by
        -#   <NaturalDocs::Version>.
        -#
        -#
        -#   Type: SymbolString
        -#
        -#   A scalar which encodes a normalized array of identifier strings representing a full or partially-resolved symbol.  All symbols
        -#   must be retrieved from plain text via <NaturalDocs::SymbolString->FromText()> so that the separation and normalization is
        -#   always consistent.  SymbolStrings are comparable via string compare functions and are sortable.
        -#
        -#
        -#   Type: ReferenceString
        -#
        -#   All the information about a reference that makes it unique encoded into a string.  This includes the <SymbolString> of the
        -#   reference, the scope <SymbolString> it appears in, the scope <SymbolStrings> it has access to via "using", and the
        -#   <ReferenceType>.  This is done because if any of those parameters change, it needs to be treated as a completely separate
        -#   reference.
        -#
        -
        -
        -
        -###############################################################################
        -# Group: Support Functions
        -# General functions that are used throughout the program, and that don't really fit anywhere else.
        -
        -
        -#
        -#   Function: StringCompare
        -#
        -#   Compares two strings so that the result is good for proper sorting.  A proper sort orders the characters as
        -#   follows:
        -#
        -#   - End of string.
        -#   - Whitespace.  Line break-tab-space.
        -#   - Symbols, which is anything not included in the other entries.
        -#   - Numbers, 0-9.
        -#   - Letters, case insensitive except to break ties.
        -#
        -#   If you use cmp instead of this function, the result would go by ASCII/Unicode values which would place certain symbols
        -#   between letters and numbers instead of having them all grouped together.  Also, you would have to choose between case
        -#   sensitivity or complete case insensitivity, in which ties are broken arbitrarily.
        -#
        -#   Returns:
        -#
        -#   Like cmp, it returns zero if A and B are equal, a positive value if A is greater than B, and a negative value if A is less than B.
        -#
        -sub StringCompare #(a, b)
        -    {
        -    my ($a, $b) = @_;
        -
        -    if (!defined $a)
        -        {
        -        if (!defined $b)
        -            {  return 0;  }
        -        else
        -            {  return -1;  };
        -        }
        -    elsif (!defined $b)
        -        {
        -        return 1;
        -        };
        -
        -    my $translatedA = lc($a);
        -    my $translatedB = lc($b);
        -
        -    $translatedA =~ tr/\n\r\t 0-9a-z/\x01\x02\x03\x04\xDB-\xFE/;
        -    $translatedB =~ tr/\n\r\t 0-9a-z/\x01\x02\x03\x04\xDB-\xFE/;
        -
        -    my $result = $translatedA cmp $translatedB;
        -
        -    if ($result == 0)
        -        {
        -        # Break the tie by comparing their case.  Lowercase before uppercase.
        -
        -        # If statement just to keep everything theoretically kosher, even though in practice we don't need this.
        -        if (ord('A') > ord('a'))
        -            {  return ($a cmp $b);  }
        -        else
        -            {  return ($b cmp $a);  };
        -        }
        -    else
        -        {  return $result;  };
        -    };
        -
        -
        -#
        -#   Function: ShortenToMatchStrings
        -#
        -#   Compares two arrayrefs and shortens the first array to only contain shared entries.  Assumes all entries are strings.
        -#
        -#   Parameters:
        -#
        -#       sharedArrayRef - The arrayref that will be shortened to only contain common elements.
        -#       compareArrayRef - The arrayref to match.
        -#
        -sub ShortenToMatchStrings #(sharedArrayRef, compareArrayRef)
        -    {
        -    my ($sharedArrayRef, $compareArrayRef) = @_;
        -
        -    my $index = 0;
        -
        -    while ($index < scalar @$sharedArrayRef && $index < scalar @$compareArrayRef &&
        -             $sharedArrayRef->[$index] eq $compareArrayRef->[$index])
        -        {  $index++;  };
        -
        -    if ($index < scalar @$sharedArrayRef)
        -        {  splice(@$sharedArrayRef, $index);  };
        -    };
        -
        -
        -#
        -#   Function: FindFirstSymbol
        -#
        -#   Searches a string for a number of symbols to see which appears first.
        -#
        -#   Parameters:
        -#
        -#       string - The string to search.
        -#       symbols - An arrayref of symbols to look for.
        -#       index - The index to start at, if any.
        -#
        -#   Returns:
        -#
        -#       The array ( index, symbol ).
        -#
        -#       index - The index the first symbol appears at, or -1 if none appear.
        -#       symbol - The symbol that appeared, or undef if none.
        -#
        -sub FindFirstSymbol #(string, symbols, index)
        -    {
        -    my ($string, $symbols, $index) = @_;
        -
        -    if (!defined $index)
        -        {  $index = 0;  };
        -
        -    my $lowestIndex = -1;
        -    my $lowestSymbol;
        -
        -    foreach my $symbol (@$symbols)
        -        {
        -        my $testIndex = index($string, $symbol, $index);
        -
        -        if ($testIndex != -1 && ($lowestIndex == -1 || $testIndex < $lowestIndex))
        -            {
        -            $lowestIndex = $testIndex;
        -            $lowestSymbol = $symbol;
        -            };
        -        };
        -
        -    return ($lowestIndex, $lowestSymbol);
        -    };
        -
        -
        -
        -
        -###############################################################################
        -#
        -#   Main Code
        -#
        -#   The order in which functions are called here is critically important.  Read the "Usage and Dependencies" sections of all the
        -#   packages before even thinking about rearranging these.
        -#
        -
        -
        -eval {
        -
        -    # Check that our required packages are okay.
        -
        -    NaturalDocs::File->CheckCompatibility();
        -
        -
        -    # Almost everything requires Settings to be initialized.
        -
        -    NaturalDocs::Settings->Load();
        -
        -
        -    NaturalDocs::Project->LoadConfigFileInfo();
        -
        -    NaturalDocs::Topics->Load();
        -    NaturalDocs::Languages->Load();
        -
        -
        -    # Migrate from the old file names that were used prior to 1.14.
        -
        -    NaturalDocs::Project->MigrateOldFiles();
        -
        -
        -    if (!NaturalDocs::Settings->IsQuiet())
        -        {  print "Finding files and detecting changes...\n";  };
        -
        -    NaturalDocs::Project->LoadSourceFileInfo();
        -    NaturalDocs::Project->LoadImageFileInfo();
        -
        -    # Register SourceDB extensions.  Order is important.
        -    NaturalDocs::ImageReferenceTable->Register();
        -
        -    NaturalDocs::SymbolTable->Load();
        -    NaturalDocs::ClassHierarchy->Load();
        -    NaturalDocs::SourceDB->Load();
        -
        -    NaturalDocs::SymbolTable->Purge();
        -    NaturalDocs::ClassHierarchy->Purge();
        -    NaturalDocs::SourceDB->PurgeDeletedSourceFiles();
        -
        -
        -    # Parse any supported files that have changed.
        -
        -    my $filesToParse = NaturalDocs::Project->FilesToParse();
        -    my $amount = scalar keys %$filesToParse;
        -
        -    if ($amount > 0)
        -        {
        -        NaturalDocs::StatusMessage->Start('Parsing ' . $amount . ' file' . ($amount > 1 ? 's' : '') . '...', $amount);
        -
        -        foreach my $file (keys %$filesToParse)
        -            {
        -            NaturalDocs::Parser->ParseForInformation($file);
        -            NaturalDocs::StatusMessage->CompletedItem();
        -            };
        -        };
        -
        -
        -    # The symbol table is now fully resolved, so we can reduce its memory footprint.
        -
        -    NaturalDocs::SymbolTable->PurgeResolvingInfo();
        -
        -
        -    # Load and update the menu file.  We need to do this after parsing so when it is updated, it will detect files where the
        -    # default menu title has changed and files that have added or deleted Natural Docs content.
        -
        -    NaturalDocs::Menu->LoadAndUpdate();
        -
        -
        -    # Build any files that need it.  This needs to be run regardless of whether there are any files to build.  It will handle its own
        -    # output messages.
        -
        -    NaturalDocs::Builder->Run();
        -
        -
        -    # Write the changes back to disk.
        -
        -    NaturalDocs::Menu->Save();
        -    NaturalDocs::Project->SaveImageFileInfo();
        -    NaturalDocs::Project->SaveSourceFileInfo();
        -    NaturalDocs::SymbolTable->Save();
        -    NaturalDocs::ClassHierarchy->Save();
        -    NaturalDocs::SourceDB->Save();
        -    NaturalDocs::Settings->Save();
        -    NaturalDocs::Topics->Save();
        -    NaturalDocs::Languages->Save();
        -
        -    # Must be done last.
        -    NaturalDocs::Project->SaveConfigFileInfo();
        -
        -    if (!NaturalDocs::Settings->IsQuiet())
        -        {  print "Done.\n";  };
        -
        -};
        -
        -if ($EVAL_ERROR)  # Oops.
        -    {
        -    NaturalDocs::Error->HandleDeath();
        -    };
        -
        diff --git a/vendor/naturaldocs/NaturalDocs.bat b/vendor/naturaldocs/NaturalDocs.bat
        deleted file mode 100644
        index 59e396319..000000000
        --- a/vendor/naturaldocs/NaturalDocs.bat
        +++ /dev/null
        @@ -1,17 +0,0 @@
        -@echo off
        -
        -set NaturalDocsParams=
        -
        -rem Shift and loop so we can get more than nine parameters.
        -rem This is especially important if we have spaces in file names.
        -
        -:MORE
        -if "%1"=="" goto NOMORE
        -set NaturalDocsParams=%NaturalDocsParams% %1
        -shift
        -goto MORE
        -:NOMORE
        -
        -perl NaturalDocs %NaturalDocsParams%
        -
        -set NaturalDocsParams=
        \ No newline at end of file
        diff --git a/vendor/naturaldocs/Styles/Default.css b/vendor/naturaldocs/Styles/Default.css
        deleted file mode 100644
        index 511703fc4..000000000
        --- a/vendor/naturaldocs/Styles/Default.css
        +++ /dev/null
        @@ -1,828 +0,0 @@
        -/*
        -   IMPORTANT: If you're editing this file in the output directory of one of
        -   your projects, your changes will be overwritten the next time you run
        -   Natural Docs.  Instead, copy this file to your project directory, make your
        -   changes, and you can use it with -s.  Even better would be to make a CSS
        -   file in your project directory with only your changes, which you can then
        -   use with -s [original style] [your changes].
        -
        -   On the other hand, if you're editing this file in the Natural Docs styles
        -   directory, the changes will automatically be applied to all your projects
        -   that use this style the next time Natural Docs is run on them.
        -
        -   This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure.
        -   Natural Docs is licensed under version 3 of the GNU Affero General Public
        -   License (AGPL).  Refer to License.txt for the complete details.
        -
        -   This file may be distributed with documentation files generated by Natural Docs.
        -   Such documentation is not covered by Natural Docs' copyright and licensing,
        -   and may have its own copyright and distribution terms as decided by its author.
        -*/
        -
        -body {
        -    font: 10pt Verdana, Arial, sans-serif;
        -    color: #000000;
        -    margin: 0; padding: 0;
        -    }
        -
        -.ContentPage,
        -.IndexPage,
        -.FramedMenuPage {
        -    background-color: #E8E8E8;
        -    }
        -.FramedContentPage,
        -.FramedIndexPage,
        -.FramedSearchResultsPage,
        -.PopupSearchResultsPage {
        -    background-color: #FFFFFF;
        -    }
        -
        -
        -a:link,
        -a:visited { color: #900000; text-decoration: none }
        -a:hover { color: #900000; text-decoration: underline }
        -a:active { color: #FF0000; text-decoration: underline }
        -
        -td {
        -    vertical-align: top }
        -
        -img { border: 0;  }
        -
        -
        -/*
        -    Comment out this line to use web-style paragraphs (blank line between
        -    paragraphs, no indent) instead of print-style paragraphs (no blank line,
        -    indented.)
        -*/
        -p {
        -    text-indent: 5ex; margin: 0 }
        -
        -
        -/*  Opera doesn't break with just wbr, but will if you add this.  */
        -.Opera wbr:after {
        -	content: "\00200B";
        -	}
        -
        -
        -/*  Blockquotes are used as containers for things that may need to scroll.  */
        -blockquote {
        -    padding: 0;
        -    margin: 0;
        -    overflow: auto;
        -    }
        -
        -
        -.Firefox1 blockquote {
        -    padding-bottom: .5em;
        -    }
        -
        -/*  Turn off scrolling when printing.  */
        -@media print {
        -    blockquote {
        -        overflow: visible;
        -        }
        -    .IE blockquote {
        -        width: auto;
        -        }
        -    }
        -
        -
        -
        -#Menu {
        -    font-size: 9pt;
        -    padding: 10px 0 0 0;
        -    }
        -.ContentPage #Menu,
        -.IndexPage #Menu {
        -    position: absolute;
        -    top: 0;
        -    left: 0;
        -    width: 31ex;
        -    overflow: hidden;
        -    }
        -.ContentPage .Firefox #Menu,
        -.IndexPage .Firefox #Menu {
        -    width: 27ex;
        -    }
        -
        -
        -    .MTitle {
        -        font-size: 16pt; font-weight: bold; font-variant: small-caps;
        -        text-align: center;
        -        padding: 5px 10px 15px 10px;
        -        border-bottom: 1px dotted #000000;
        -        margin-bottom: 15px }
        -
        -    .MSubTitle {
        -        font-size: 9pt; font-weight: normal; font-variant: normal;
        -        margin-top: 1ex; margin-bottom: 5px }
        -
        -
        -    .MEntry a:link,
        -    .MEntry a:hover,
        -    .MEntry a:visited { color: #606060; margin-right: 0 }
        -    .MEntry a:active { color: #A00000; margin-right: 0 }
        -
        -
        -    .MGroup {
        -        font-variant: small-caps; font-weight: bold;
        -        margin: 1em 0 1em 10px;
        -        }
        -
        -    .MGroupContent {
        -        font-variant: normal; font-weight: normal }
        -
        -    .MGroup a:link,
        -    .MGroup a:hover,
        -    .MGroup a:visited { color: #545454; margin-right: 10px }
        -    .MGroup a:active { color: #A00000; margin-right: 10px }
        -
        -
        -    .MFile,
        -    .MText,
        -    .MLink,
        -    .MIndex {
        -        padding: 1px 17px 2px 10px;
        -        margin: .25em 0 .25em 0;
        -        }
        -
        -    .MText {
        -        font-size: 8pt; font-style: italic }
        -
        -    .MLink {
        -        font-style: italic }
        -
        -    #MSelected {
        -        color: #000000; background-color: #FFFFFF;
        -        /*  Replace padding with border.  */
        -        padding: 0 10px 0 10px;
        -        border-width: 1px 2px 2px 0; border-style: solid; border-color: #000000;
        -        margin-right: 5px;
        -        }
        -
        -    /*  Close off the left side when its in a group.  */
        -    .MGroup #MSelected {
        -        padding-left: 9px; border-left-width: 1px }
        -
        -    /*  A treat for Mozilla users.  Blatantly non-standard.  Will be replaced with CSS 3 attributes when finalized/supported.  */
        -    .Firefox #MSelected {
        -        -moz-border-radius-topright: 10px;
        -        -moz-border-radius-bottomright: 10px }
        -    .Firefox .MGroup #MSelected {
        -        -moz-border-radius-topleft: 10px;
        -        -moz-border-radius-bottomleft: 10px }
        -
        -
        -    #MSearchPanel {
        -        padding: 0px 6px;
        -        margin: .25em 0;
        -        }
        -
        -
        -    #MSearchField {
        -        font: italic 9pt Verdana, sans-serif;
        -        color: #606060;
        -        background-color: #E8E8E8;
        -        border: none;
        -        padding: 2px 4px;
        -        width: 100%;
        -        }
        -    /* Only Opera gets it right. */
        -    .Firefox #MSearchField,
        -    .IE #MSearchField,
        -    .Safari #MSearchField {
        -        width: 94%;
        -        }
        -    .Opera9 #MSearchField,
        -    .Konqueror #MSearchField {
        -        width: 97%;
        -        }
        -    .FramedMenuPage .Firefox #MSearchField,
        -    .FramedMenuPage .Safari #MSearchField,
        -    .FramedMenuPage .Konqueror #MSearchField {
        -        width: 98%;
        -        }
        -
        -    /* Firefox doesn't do this right in frames without #MSearchPanel added on.
        -        It's presence doesn't hurt anything other browsers. */
        -    #MSearchPanel.MSearchPanelInactive:hover #MSearchField {
        -        background-color: #FFFFFF;
        -        border: 1px solid #C0C0C0;
        -        padding: 1px 3px;
        -        }
        -    .MSearchPanelActive #MSearchField {
        -        background-color: #FFFFFF;
        -        border: 1px solid #C0C0C0;
        -        font-style: normal;
        -        padding: 1px 3px;
        -        }
        -
        -    #MSearchType {
        -        visibility: hidden;
        -        font: 8pt Verdana, sans-serif;
        -        width: 98%;
        -        padding: 0;
        -        border: 1px solid #C0C0C0;
        -        }
        -    .MSearchPanelActive #MSearchType,
        -    /*  As mentioned above, Firefox doesn't do this right in frames without #MSearchPanel added on. */
        -    #MSearchPanel.MSearchPanelInactive:hover #MSearchType,
        -    #MSearchType:focus {
        -        visibility: visible;
        -        color: #606060;
        -        }
        -    #MSearchType option#MSearchEverything {
        -        font-weight: bold;
        -        }
        -
        -    .Opera8 .MSearchPanelInactive:hover,
        -    .Opera8 .MSearchPanelActive {
        -        margin-left: -1px;
        -        }
        -
        -
        -    iframe#MSearchResults {
        -        width: 60ex;
        -        height: 15em;
        -        }
        -    #MSearchResultsWindow {
        -        display: none;
        -        position: absolute;
        -        left: 0; top: 0;
        -        border: 1px solid #000000;
        -        background-color: #E8E8E8;
        -        }
        -    #MSearchResultsWindowClose {
        -        font-weight: bold;
        -        font-size: 8pt;
        -        display: block;
        -        padding: 2px 5px;
        -        }
        -    #MSearchResultsWindowClose:link,
        -    #MSearchResultsWindowClose:visited {
        -        color: #000000;
        -        text-decoration: none;
        -        }
        -    #MSearchResultsWindowClose:active,
        -    #MSearchResultsWindowClose:hover {
        -        color: #800000;
        -        text-decoration: none;
        -        background-color: #F4F4F4;
        -        }
        -
        -
        -
        -
        -#Content {
        -    padding-bottom: 15px;
        -    }
        -
        -.ContentPage #Content {
        -    border-width: 0 0 1px 1px;
        -    border-style: solid;
        -    border-color: #000000;
        -    background-color: #FFFFFF;
        -    font-size: 9pt;  /* To make 31ex match the menu's 31ex. */
        -    margin-left: 31ex;
        -    }
        -.ContentPage .Firefox #Content {
        -    margin-left: 27ex;
        -    }
        -
        -
        -
        -    .CTopic {
        -        font-size: 10pt;
        -        margin-bottom: 3em;
        -        }
        -
        -
        -    .CTitle {
        -        font-size: 12pt; font-weight: bold;
        -        border-width: 0 0 1px 0; border-style: solid; border-color: #A0A0A0;
        -        margin: 0 15px .5em 15px }
        -
        -    .CGroup .CTitle {
        -        font-size: 16pt; font-variant: small-caps;
        -        padding-left: 15px; padding-right: 15px;
        -        border-width: 0 0 2px 0; border-color: #000000;
        -        margin-left: 0; margin-right: 0 }
        -
        -    .CClass .CTitle,
        -    .CInterface .CTitle,
        -    .CDatabase .CTitle,
        -    .CDatabaseTable .CTitle,
        -    .CSection .CTitle {
        -        font-size: 18pt;
        -        color: #FFFFFF; background-color: #A0A0A0;
        -        padding: 10px 15px 10px 15px;
        -        border-width: 2px 0; border-color: #000000;
        -        margin-left: 0; margin-right: 0 }
        -
        -    #MainTopic .CTitle {
        -        font-size: 20pt;
        -        color: #FFFFFF; background-color: #7070C0;
        -        padding: 10px 15px 10px 15px;
        -        border-width: 0 0 3px 0; border-color: #000000;
        -        margin-left: 0; margin-right: 0 }
        -
        -    .CBody {
        -        margin-left: 15px; margin-right: 15px }
        -
        -
        -    .CToolTip {
        -        position: absolute; visibility: hidden;
        -        left: 0; top: 0;
        -        background-color: #FFFFE0;
        -        padding: 5px;
        -        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #000000;
        -        font-size: 8pt;
        -        }
        -
        -    .Opera .CToolTip {
        -        max-width: 98%;
        -        }
        -
        -    /*  Scrollbars would be useless.  */
        -    .CToolTip blockquote {
        -        overflow: hidden;
        -        }
        -    .IE6 .CToolTip blockquote {
        -        overflow: visible;
        -        }
        -
        -    .CHeading {
        -        font-weight: bold; font-size: 10pt;
        -        margin: 1.5em 0 .5em 0;
        -        }
        -
        -    .CBody pre {
        -        font: 10pt "Courier New", Courier, monospace;
        -	    background-color: #FCFCFC;
        -	    margin: 1em 35px;
        -	    padding: 10px 15px 10px 10px;
        -	    border-color: #E0E0E0 #E0E0E0 #E0E0E0 #E4E4E4;
        -	    border-width: 1px 1px 1px 6px;
        -	    border-style: dashed dashed dashed solid;
        -        }
        -
        -    .CBody ul {
        -        /*  I don't know why CBody's margin doesn't apply, but it's consistent across browsers so whatever.
        -             Reapply it here as padding.  */
        -        padding-left: 15px; padding-right: 15px;
        -        margin: .5em 5ex .5em 5ex;
        -        }
        -
        -    .CDescriptionList {
        -        margin: .5em 5ex 0 5ex }
        -
        -        .CDLEntry {
        -            font: 10pt "Courier New", Courier, monospace; color: #808080;
        -            padding-bottom: .25em;
        -            white-space: nowrap }
        -
        -        .CDLDescription {
        -            font-size: 10pt;  /*  For browsers that don't inherit correctly, like Opera 5.  */
        -            padding-bottom: .5em; padding-left: 5ex }
        -
        -
        -    .CTopic img {
        -        text-align: center;
        -        display: block;
        -        margin: 1em auto;
        -        }
        -    .CImageCaption {
        -        font-variant: small-caps;
        -        font-size: 8pt;
        -        color: #808080;
        -        text-align: center;
        -        position: relative;
        -        top: 1em;
        -        }
        -
        -    .CImageLink {
        -        color: #808080;
        -        font-style: italic;
        -        }
        -    a.CImageLink:link,
        -    a.CImageLink:visited,
        -    a.CImageLink:hover { color: #808080 }
        -
        -
        -
        -
        -
        -.Prototype {
        -    font: 10pt "Courier New", Courier, monospace;
        -    padding: 5px 3ex;
        -    border-width: 1px; border-style: solid;
        -    margin: 0 5ex 1.5em 5ex;
        -    }
        -
        -    .Prototype td {
        -        font-size: 10pt;
        -        }
        -
        -    .PDefaultValue,
        -    .PDefaultValuePrefix,
        -    .PTypePrefix {
        -        color: #8F8F8F;
        -        }
        -    .PTypePrefix {
        -        text-align: right;
        -        }
        -    .PAfterParameters {
        -        vertical-align: bottom;
        -        }
        -
        -    .IE .Prototype table {
        -        padding: 0;
        -        }
        -
        -    .CFunction .Prototype {
        -        background-color: #F4F4F4; border-color: #D0D0D0 }
        -    .CProperty .Prototype {
        -        background-color: #F4F4FF; border-color: #C0C0E8 }
        -    .CVariable .Prototype {
        -        background-color: #FFFFF0; border-color: #E0E0A0 }
        -
        -    .CClass .Prototype {
        -        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0;
        -        background-color: #F4F4F4;
        -        }
        -    .CInterface .Prototype {
        -        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0D0;
        -        background-color: #F4F4FF;
        -        }
        -
        -    .CDatabaseIndex .Prototype,
        -    .CConstant .Prototype {
        -        background-color: #D0D0D0; border-color: #000000 }
        -    .CType .Prototype,
        -    .CEnumeration .Prototype {
        -        background-color: #FAF0F0; border-color: #E0B0B0;
        -        }
        -    .CDatabaseTrigger .Prototype,
        -    .CEvent .Prototype,
        -    .CDelegate .Prototype {
        -        background-color: #F0FCF0; border-color: #B8E4B8 }
        -
        -    .CToolTip .Prototype {
        -        margin: 0 0 .5em 0;
        -        white-space: nowrap;
        -        }
        -
        -
        -
        -
        -
        -.Summary {
        -    margin: 1.5em 5ex 0 5ex }
        -
        -    .STitle {
        -        font-size: 12pt; font-weight: bold;
        -        margin-bottom: .5em }
        -
        -
        -    .SBorder {
        -        background-color: #FFFFF0;
        -        padding: 15px;
        -        border: 1px solid #C0C060 }
        -
        -    /* In a frame IE 6 will make them too long unless you set the width to 100%.  Without frames it will be correct without a width
        -        or slightly too long (but not enough to scroll) with a width.  This arbitrary weirdness simply astounds me.  IE 7 has the same
        -        problem with frames, haven't tested it without.  */
        -    .FramedContentPage .IE .SBorder {
        -        width: 100% }
        -
        -    /*  A treat for Mozilla users.  Blatantly non-standard.  Will be replaced with CSS 3 attributes when finalized/supported.  */
        -    .Firefox .SBorder {
        -        -moz-border-radius: 20px }
        -
        -
        -    .STable {
        -        font-size: 9pt; width: 100% }
        -
        -    .SEntry {
        -        width: 30% }
        -    .SDescription {
        -        width: 70% }
        -
        -
        -    .SMarked {
        -        background-color: #F8F8D8 }
        -
        -    .SDescription { padding-left: 2ex }
        -    .SIndent1 .SEntry { padding-left: 1.5ex }   .SIndent1 .SDescription { padding-left: 3.5ex }
        -    .SIndent2 .SEntry { padding-left: 3.0ex }   .SIndent2 .SDescription { padding-left: 5.0ex }
        -    .SIndent3 .SEntry { padding-left: 4.5ex }   .SIndent3 .SDescription { padding-left: 6.5ex }
        -    .SIndent4 .SEntry { padding-left: 6.0ex }   .SIndent4 .SDescription { padding-left: 8.0ex }
        -    .SIndent5 .SEntry { padding-left: 7.5ex }   .SIndent5 .SDescription { padding-left: 9.5ex }
        -
        -    .SDescription a { color: #800000}
        -    .SDescription a:active { color: #A00000 }
        -
        -    .SGroup td {
        -        padding-top: .5em; padding-bottom: .25em }
        -
        -    .SGroup .SEntry {
        -        font-weight: bold; font-variant: small-caps }
        -
        -    .SGroup .SEntry a { color: #800000 }
        -    .SGroup .SEntry a:active { color: #F00000 }
        -
        -
        -    .SMain td,
        -    .SClass td,
        -    .SDatabase td,
        -    .SDatabaseTable td,
        -    .SSection td {
        -        font-size: 10pt;
        -        padding-bottom: .25em }
        -
        -    .SClass td,
        -    .SDatabase td,
        -    .SDatabaseTable td,
        -    .SSection td {
        -        padding-top: 1em }
        -
        -    .SMain .SEntry,
        -    .SClass .SEntry,
        -    .SDatabase .SEntry,
        -    .SDatabaseTable .SEntry,
        -    .SSection .SEntry {
        -        font-weight: bold;
        -        }
        -
        -    .SMain .SEntry a,
        -    .SClass .SEntry a,
        -    .SDatabase .SEntry a,
        -    .SDatabaseTable .SEntry a,
        -    .SSection .SEntry a { color: #000000 }
        -
        -    .SMain .SEntry a:active,
        -    .SClass .SEntry a:active,
        -    .SDatabase .SEntry a:active,
        -    .SDatabaseTable .SEntry a:active,
        -    .SSection .SEntry a:active { color: #A00000 }
        -
        -
        -
        -
        -
        -.ClassHierarchy {
        -    margin: 0 15px 1em 15px }
        -
        -    .CHEntry {
        -        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0;
        -        margin-bottom: 3px;
        -        padding: 2px 2ex;
        -        font-size: 10pt;
        -        background-color: #F4F4F4; color: #606060;
        -        }
        -
        -    .Firefox .CHEntry {
        -        -moz-border-radius: 4px;
        -        }
        -
        -    .CHCurrent .CHEntry {
        -        font-weight: bold;
        -        border-color: #000000;
        -        color: #000000;
        -        }
        -
        -    .CHChildNote .CHEntry {
        -        font-style: italic;
        -        font-size: 8pt;
        -        }
        -
        -    .CHIndent {
        -        margin-left: 3ex;
        -        }
        -
        -    .CHEntry a:link,
        -    .CHEntry a:visited,
        -    .CHEntry a:hover {
        -        color: #606060;
        -        }
        -    .CHEntry a:active {
        -        color: #800000;
        -        }
        -
        -
        -
        -
        -
        -#Index {
        -    background-color: #FFFFFF;
        -    }
        -
        -/*  As opposed to .PopupSearchResultsPage #Index  */
        -.IndexPage #Index,
        -.FramedIndexPage #Index,
        -.FramedSearchResultsPage #Index {
        -    padding: 15px;
        -    }
        -
        -.IndexPage #Index {
        -    border-width: 0 0 1px 1px;
        -    border-style: solid;
        -    border-color: #000000;
        -    font-size: 9pt;  /* To make 27ex match the menu's 27ex. */
        -    margin-left: 27ex;
        -    }
        -
        -
        -    .IPageTitle {
        -        font-size: 20pt; font-weight: bold;
        -        color: #FFFFFF; background-color: #7070C0;
        -        padding: 10px 15px 10px 15px;
        -        border-width: 0 0 3px 0; border-color: #000000; border-style: solid;
        -        margin: -15px -15px 0 -15px }
        -
        -    .FramedSearchResultsPage .IPageTitle {
        -        margin-bottom: 15px;
        -        }
        -
        -    .INavigationBar {
        -        font-size: 10pt;
        -        text-align: center;
        -        background-color: #FFFFF0;
        -        padding: 5px;
        -        border-bottom: solid 1px black;
        -        margin: 0 -15px 15px -15px;
        -        }
        -
        -    .INavigationBar a {
        -        font-weight: bold }
        -
        -    .IHeading {
        -        font-size: 16pt; font-weight: bold;
        -        padding: 2.5em 0 .5em 0;
        -        text-align: center;
        -        width: 3.5ex;
        -        }
        -    #IFirstHeading {
        -        padding-top: 0;
        -        }
        -
        -    .IEntry {
        -        font-size: 10pt;
        -        padding-left: 1ex;
        -        }
        -    .PopupSearchResultsPage .IEntry {
        -        font-size: 8pt;
        -        padding: 1px 5px;
        -        }
        -    .PopupSearchResultsPage .Opera9 .IEntry,
        -    .FramedSearchResultsPage .Opera9 .IEntry {
        -        text-align: left;
        -        }
        -    .FramedSearchResultsPage .IEntry {
        -        padding: 0;
        -        }
        -
        -    .ISubIndex {
        -        padding-left: 3ex; padding-bottom: .5em }
        -    .PopupSearchResultsPage .ISubIndex {
        -        display: none;
        -        }
        -
        -    /*  While it may cause some entries to look like links when they aren't, I found it's much easier to read the
        -         index if everything's the same color.  */
        -    .ISymbol {
        -        font-weight: bold; color: #900000  }
        -
        -    .IndexPage .ISymbolPrefix,
        -    .FramedIndexPage .ISymbolPrefix {
        -        font-size: 10pt;
        -        text-align: right;
        -        color: #C47C7C;
        -        background-color: #F8F8F8;
        -        border-right: 3px solid #E0E0E0;
        -        border-left: 1px solid #E0E0E0;
        -        padding: 0 1px 0 2px;
        -        }
        -    .PopupSearchResultsPage .ISymbolPrefix,
        -    .FramedSearchResultsPage .ISymbolPrefix {
        -        color: #900000;
        -        }
        -    .PopupSearchResultsPage .ISymbolPrefix {
        -        font-size: 8pt;
        -        }
        -
        -    .IndexPage #IFirstSymbolPrefix,
        -    .FramedIndexPage #IFirstSymbolPrefix {
        -        border-top: 1px solid #E0E0E0;
        -        }
        -    .IndexPage #ILastSymbolPrefix,
        -    .FramedIndexPage #ILastSymbolPrefix {
        -        border-bottom: 1px solid #E0E0E0;
        -        }
        -    .IndexPage #IOnlySymbolPrefix,
        -    .FramedIndexPage #IOnlySymbolPrefix {
        -        border-top: 1px solid #E0E0E0;
        -        border-bottom: 1px solid #E0E0E0;
        -        }
        -
        -    a.IParent,
        -    a.IFile {
        -        display: block;
        -        }
        -
        -    .PopupSearchResultsPage .SRStatus {
        -        padding: 2px 5px;
        -        font-size: 8pt;
        -        font-style: italic;
        -        }
        -    .FramedSearchResultsPage .SRStatus {
        -        font-size: 10pt;
        -        font-style: italic;
        -        }
        -
        -    .SRResult {
        -        display: none;
        -        }
        -
        -
        -
        -#Footer {
        -    font-size: 8pt;
        -    color: #989898;
        -    text-align: right;
        -    }
        -
        -#Footer p {
        -    text-indent: 0;
        -    margin-bottom: .5em;
        -    }
        -
        -.ContentPage #Footer,
        -.IndexPage #Footer {
        -    text-align: right;
        -    margin: 2px;
        -    }
        -
        -.FramedMenuPage #Footer {
        -    text-align: center;
        -    margin: 5em 10px 10px 10px;
        -    padding-top: 1em;
        -    border-top: 1px solid #C8C8C8;
        -    }
        -
        -    #Footer a:link,
        -    #Footer a:hover,
        -    #Footer a:visited { color: #989898 }
        -    #Footer a:active { color: #A00000 }
        -
        -
        -
        -.prettyprint .kwd { color: #800000; }  /* keywords */
        -
        -    .prettyprint.PDefaultValue .kwd,
        -    .prettyprint.PDefaultValuePrefix .kwd,
        -    .prettyprint.PTypePrefix .kwd {
        -        color: #C88F8F;
        -        }
        -
        -.prettyprint .com { color: #008000; }  /* comments */
        -
        -    .prettyprint.PDefaultValue .com,
        -    .prettyprint.PDefaultValuePrefix .com,
        -    .prettyprint.PTypePrefix .com {
        -        color: #8FC88F;
        -        }
        -
        -.prettyprint .str { color: #0000B0; }  /* strings */
        -.prettyprint .lit { color: #0000B0; }  /* literals */
        -
        -    .prettyprint.PDefaultValue .str,
        -    .prettyprint.PDefaultValuePrefix .str,
        -    .prettyprint.PTypePrefix .str,
        -    .prettyprint.PDefaultValue .lit,
        -    .prettyprint.PDefaultValuePrefix .lit,
        -    .prettyprint.PTypePrefix .lit {
        -        color: #8F8FC0;
        -        }
        -
        -.prettyprint .typ { color: #000000; }  /* types */
        -.prettyprint .pun { color: #000000; }  /* punctuation */
        -.prettyprint .pln { color: #000000; }  /* punctuation */
        -
        -    .prettyprint.PDefaultValue .typ,
        -    .prettyprint.PDefaultValuePrefix .typ,
        -    .prettyprint.PTypePrefix .typ,
        -    .prettyprint.PDefaultValue .pun,
        -    .prettyprint.PDefaultValuePrefix .pun,
        -    .prettyprint.PTypePrefix .pun,
        -    .prettyprint.PDefaultValue .pln,
        -    .prettyprint.PDefaultValuePrefix .pln,
        -    .prettyprint.PTypePrefix .pln {
        -        color: #8F8F8F;
        -        }
        -
        -.prettyprint .tag { color: #008; }
        -.prettyprint .atn { color: #606; }
        -.prettyprint .atv { color: #080; }
        -.prettyprint .dec { color: #606; }
        -
        diff --git a/vendor/naturaldocs/Styles/Roman.css b/vendor/naturaldocs/Styles/Roman.css
        deleted file mode 100644
        index 6c3f0cd72..000000000
        --- a/vendor/naturaldocs/Styles/Roman.css
        +++ /dev/null
        @@ -1,826 +0,0 @@
        -/*
        -   IMPORTANT: If you're editing this file in the output directory of one of
        -   your projects, your changes will be overwritten the next time you run
        -   Natural Docs.  Instead, copy this file to your project directory, make your
        -   changes, and you can use it with -s.  Even better would be to make a CSS
        -   file in your project directory with only your changes, which you can then
        -   use with -s [original style] [your changes].
        -
        -   On the other hand, if you're editing this file in the Natural Docs styles
        -   directory, the changes will automatically be applied to all your projects
        -   that use this style the next time Natural Docs is run on them.
        -
        -   This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure.
        -   Natural Docs is licensed under version 3 of the GNU Affero General Public
        -   License (AGPL).  Refer to License.txt for the complete details.
        -
        -   This file may be distributed with documentation files generated by Natural Docs.
        -   Such documentation is not covered by Natural Docs' copyright and licensing,
        -   and may have its own copyright and distribution terms as decided by its author.
        -*/
        -
        -body {
        -    font: 12pt "Times New Roman", Roman, serif;
        -    color: #000000;
        -    margin: 0; padding: 0;
        -    }
        -
        -.ContentPage,
        -.IndexPage,
        -.FramedMenuPage {
        -    background-color: #E8E8E8;
        -    }
        -.FramedContentPage,
        -.FramedIndexPage,
        -.FramedSearchResultsPage,
        -.PopupSearchResultsPage {
        -    background-color: #FFFFFF;
        -    }
        -
        -
        -a:link,
        -a:visited { color: #900000; text-decoration: none }
        -a:hover { color: #900000; text-decoration: underline }
        -a:active { color: #FF0000; text-decoration: underline }
        -
        -td {
        -    vertical-align: top }
        -
        -img { border: 0;  }
        -
        -
        -/*
        -    Comment out this line to use web-style paragraphs (blank line between
        -    paragraphs, no indent) instead of print-style paragraphs (no blank line,
        -    indented.)
        -*/
        -p {
        -    text-indent: 5ex; margin: 0 }
        -
        -
        -/*  Opera doesn't break with just wbr, but will if you add this.  */
        -.Opera wbr:after {
        -	content: "\00200B";
        -	}
        -
        -/*  Blockquotes are used as containers for things that may need to scroll.  */
        -blockquote {
        -    padding: 0;
        -    margin: 0;
        -    overflow: auto;
        -    }
        -
        -
        -.Firefox1 blockquote {
        -    padding-bottom: .5em;
        -    }
        -
        -/*  Turn off scrolling when printing.  */
        -@media print {
        -    blockquote {
        -        overflow: visible;
        -        }
        -    .IE blockquote {
        -        width: auto;
        -        }
        -    }
        -
        -
        -
        -#Menu {
        -    font-size: 10pt;
        -    padding: 10px 0 0 0;
        -    }
        -.ContentPage #Menu,
        -.IndexPage #Menu {
        -    position: absolute;
        -    top: 0;
        -    left: 0;
        -    width: 31ex;
        -    overflow: hidden;
        -    }
        -.ContentPage .Firefox #Menu,
        -.IndexPage .Firefox #Menu {
        -    width: 27ex;
        -    }
        -
        -
        -    .MTitle {
        -        font-size: 18pt; font-weight: bold; font-variant: small-caps;
        -        text-align: center;
        -        padding: 5px 10px 15px 10px;
        -        border-bottom: 1px dotted #000000;
        -        margin-bottom: 15px }
        -
        -    .MSubTitle {
        -        font-size: 10pt; font-weight: normal; font-variant: normal;
        -        margin-top: 1ex; margin-bottom: 5px }
        -
        -
        -    .MEntry a:link,
        -    .MEntry a:hover,
        -    .MEntry a:visited { color: #606060; margin-right: 0 }
        -    .MEntry a:active { color: #A00000; margin-right: 0 }
        -
        -
        -    .MGroup {
        -        font-variant: small-caps; font-weight: bold;
        -        margin: 1em 0 1em 10px;
        -        }
        -
        -    .MGroupContent {
        -        font-variant: normal; font-weight: normal }
        -
        -    .MGroup a:link,
        -    .MGroup a:hover,
        -    .MGroup a:visited { color: #545454; margin-right: 10px }
        -    .MGroup a:active { color: #A00000; margin-right: 10px }
        -
        -
        -    .MFile,
        -    .MText,
        -    .MLink,
        -    .MIndex {
        -        padding: 1px 17px 2px 10px;
        -        margin: .25em 0 .25em 0;
        -        }
        -
        -    .MText {
        -        font-size: 8pt; font-style: italic }
        -
        -    .MLink {
        -        font-style: italic }
        -
        -    #MSelected {
        -        color: #000000; background-color: #FFFFFF;
        -        /*  Replace padding with border.  */
        -        padding: 0 10px 0 10px;
        -        border-width: 1px 2px 2px 0; border-style: solid; border-color: #000000;
        -        margin-right: 5px;
        -        }
        -
        -    /*  Close off the left side when its in a group.  */
        -    .MGroup #MSelected {
        -        padding-left: 9px; border-left-width: 1px }
        -
        -    /*  A treat for Mozilla users.  Blatantly non-standard.  Will be replaced with CSS 3 attributes when finalized/supported.  */
        -    .Firefox #MSelected {
        -        -moz-border-radius-topright: 10px;
        -        -moz-border-radius-bottomright: 10px }
        -    .Firefox .MGroup #MSelected {
        -        -moz-border-radius-topleft: 10px;
        -        -moz-border-radius-bottomleft: 10px }
        -
        -
        -    #MSearchPanel {
        -        padding: 0px 6px;
        -        margin: .25em 0;
        -        }
        -
        -
        -    #MSearchField {
        -        font: italic 10pt "Times New Roman", Roman, serif;
        -        color: #606060;
        -        background-color: #E8E8E8;
        -        border: none;
        -        padding: 2px 4px;
        -        width: 100%;
        -        }
        -    /* Only Opera gets it right. */
        -    .Firefox #MSearchField,
        -    .IE #MSearchField,
        -    .Safari #MSearchField {
        -        width: 94%;
        -        }
        -    .Opera9 #MSearchField,
        -    .Konqueror #MSearchField {
        -        width: 97%;
        -        }
        -    .FramedMenuPage .Firefox #MSearchField,
        -    .FramedMenuPage .Safari #MSearchField,
        -    .FramedMenuPage .Konqueror #MSearchField {
        -        width: 98%;
        -        }
        -
        -    /* Firefox doesn't do this right in frames without #MSearchPanel added on.
        -        It's presence doesn't hurt anything other browsers. */
        -    #MSearchPanel.MSearchPanelInactive:hover #MSearchField {
        -        background-color: #FFFFFF;
        -        border: 1px solid #C0C0C0;
        -        padding: 1px 3px;
        -        }
        -    .MSearchPanelActive #MSearchField {
        -        background-color: #FFFFFF;
        -        border: 1px solid #C0C0C0;
        -        font-style: normal;
        -        padding: 1px 3px;
        -        }
        -
        -    #MSearchType {
        -        visibility: hidden;
        -        font: 10pt "Times New Roman", Roman, serif;
        -        width: 98%;
        -        padding: 0;
        -        border: 1px solid #C0C0C0;
        -        }
        -    .MSearchPanelActive #MSearchType,
        -    /*  As mentioned above, Firefox doesn't do this right in frames without #MSearchPanel added on. */
        -    #MSearchPanel.MSearchPanelInactive:hover #MSearchType,
        -    #MSearchType:focus {
        -        visibility: visible;
        -        color: #606060;
        -        }
        -    #MSearchType option#MSearchEverything {
        -        font-weight: bold;
        -        }
        -
        -    .Opera8 .MSearchPanelInactive:hover,
        -    .Opera8 .MSearchPanelActive {
        -        margin-left: -1px;
        -        }
        -
        -
        -    iframe#MSearchResults {
        -        width: 60ex;
        -        height: 15em;
        -        }
        -    #MSearchResultsWindow {
        -        display: none;
        -        position: absolute;
        -        left: 0; top: 0;
        -        border: 1px solid #000000;
        -        background-color: #E8E8E8;
        -        }
        -    #MSearchResultsWindowClose {
        -        font-weight: bold;
        -        font-size: 8pt;
        -        display: block;
        -        padding: 2px 5px;
        -        }
        -    #MSearchResultsWindowClose:link,
        -    #MSearchResultsWindowClose:visited {
        -        color: #000000;
        -        text-decoration: none;
        -        }
        -    #MSearchResultsWindowClose:active,
        -    #MSearchResultsWindowClose:hover {
        -        color: #800000;
        -        text-decoration: none;
        -        background-color: #F4F4F4;
        -        }
        -
        -
        -
        -
        -#Content {
        -    padding-bottom: 15px;
        -    }
        -
        -.ContentPage #Content {
        -    border-width: 0 0 1px 1px;
        -    border-style: solid;
        -    border-color: #000000;
        -    background-color: #FFFFFF;
        -    font-size: 10pt;  /* To make 31ex match the menu's 31ex. */
        -    margin-left: 31ex;
        -    }
        -.ContentPage .Firefox #Content {
        -    margin-left: 27ex;
        -    }
        -
        -
        -
        -    .CTopic {
        -        font-size: 12pt;
        -        margin-bottom: 3em;
        -        }
        -
        -
        -    .CTitle {
        -        font-size: 16pt; font-weight: bold;
        -        border-width: 0 0 1px 0; border-style: solid; border-color: #A0A0A0;
        -        margin: 0 15px .5em 15px }
        -
        -    .CGroup .CTitle {
        -        font-size: 18pt; font-variant: small-caps;
        -        padding-left: 15px; padding-right: 15px;
        -        border-width: 0 0 2px 0; border-color: #000000;
        -        margin-left: 0; margin-right: 0 }
        -
        -    .CClass .CTitle,
        -    .CInterface .CTitle,
        -    .CDatabase .CTitle,
        -    .CDatabaseTable .CTitle,
        -    .CSection .CTitle {
        -        font-size: 20pt;
        -        color: #FFFFFF; background-color: #A0A0A0;
        -        padding: 10px 15px 10px 15px;
        -        border-width: 2px 0; border-color: #000000;
        -        margin-left: 0; margin-right: 0 }
        -
        -    #MainTopic .CTitle {
        -        font-size: 24pt;
        -        color: #FFFFFF; background-color: #7070C0;
        -        padding: 10px 15px 10px 15px;
        -        border-width: 0 0 3px 0; border-color: #000000;
        -        margin-left: 0; margin-right: 0 }
        -
        -    .CBody {
        -        margin-left: 15px; margin-right: 15px }
        -
        -
        -    .CToolTip {
        -        position: absolute; visibility: hidden;
        -        left: 0; top: 0;
        -        background-color: #FFFFE0;
        -        padding: 5px;
        -        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #000000;
        -        font-size: 10pt;
        -        }
        -
        -    .Opera .CToolTip {
        -        max-width: 98%;
        -        }
        -
        -    /*  Scrollbars would be useless.  */
        -    .CToolTip blockquote {
        -        overflow: hidden;
        -        }
        -    .IE6 .CToolTip blockquote {
        -        overflow: visible;
        -        }
        -
        -    .CHeading {
        -        font-weight: bold; font-size: 10pt;
        -        margin: 1.5em 0 .5em 0;
        -        }
        -
        -    .CBody pre {
        -        font: 10pt "Courier New", Courier, monospace;
        -	    background-color: #FCFCFC;
        -	    margin: 1em 35px;
        -	    padding: 10px 15px 10px 10px;
        -	    border-color: #E0E0E0 #E0E0E0 #E0E0E0 #E4E4E4;
        -	    border-width: 1px 1px 1px 6px;
        -	    border-style: dashed dashed dashed solid;
        -        }
        -
        -    .CBody ul {
        -        /*  I don't know why CBody's margin doesn't apply, but it's consistent across browsers so whatever.
        -             Reapply it here as padding.  */
        -        padding-left: 15px; padding-right: 15px;
        -        margin: .5em 5ex .5em 5ex;
        -        }
        -
        -    .CDescriptionList {
        -        margin: .5em 5ex 0 5ex }
        -
        -        .CDLEntry {
        -            font: 10pt "Courier New", Courier, monospace; color: #808080;
        -            padding-bottom: .25em;
        -            white-space: nowrap }
        -
        -        .CDLDescription {
        -            font-size: 12pt;  /*  For browsers that don't inherit correctly, like Opera 5.  */
        -            padding-bottom: .5em; padding-left: 5ex }
        -
        -
        -    .CTopic img {
        -        text-align: center;
        -        display: block;
        -        margin: 1em auto;
        -        }
        -    .CImageCaption {
        -        font-variant: small-caps;
        -        font-size: 10pt;
        -        color: #808080;
        -        text-align: center;
        -        position: relative;
        -        top: 1em;
        -        }
        -
        -    .CImageLink {
        -        color: #808080;
        -        font-style: italic;
        -        }
        -    a.CImageLink:link,
        -    a.CImageLink:visited,
        -    a.CImageLink:hover { color: #808080 }
        -
        -
        -
        -
        -
        -.Prototype {
        -    font: 10pt "Courier New", Courier, monospace;
        -    padding: 5px 3ex;
        -    border-width: 1px; border-style: solid;
        -    margin: 0 5ex 1.5em 5ex;
        -    }
        -
        -    .Prototype td {
        -        font-size: 10pt;
        -        }
        -
        -    .PDefaultValue,
        -    .PDefaultValuePrefix,
        -    .PTypePrefix {
        -        color: #8F8F8F;
        -        }
        -    .PTypePrefix {
        -        text-align: right;
        -        }
        -    .PAfterParameters {
        -        vertical-align: bottom;
        -        }
        -
        -    .IE .Prototype table {
        -        padding: 0;
        -        }
        -
        -    .CFunction .Prototype {
        -        background-color: #F4F4F4; border-color: #D0D0D0 }
        -    .CProperty .Prototype {
        -        background-color: #F4F4FF; border-color: #C0C0E8 }
        -    .CVariable .Prototype {
        -        background-color: #FFFFF0; border-color: #E0E0A0 }
        -
        -    .CClass .Prototype {
        -        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0;
        -        background-color: #F4F4F4;
        -        }
        -    .CInterface .Prototype {
        -        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0D0;
        -        background-color: #F4F4FF;
        -        }
        -
        -    .CDatabaseIndex .Prototype,
        -    .CConstant .Prototype {
        -        background-color: #D0D0D0; border-color: #000000 }
        -    .CType .Prototype,
        -    .CEnumeration .Prototype {
        -        background-color: #FAF0F0; border-color: #E0B0B0;
        -        }
        -    .CDatabaseTrigger .Prototype,
        -    .CEvent .Prototype,
        -    .CDelegate .Prototype {
        -        background-color: #F0FCF0; border-color: #B8E4B8 }
        -
        -    .CToolTip .Prototype {
        -        margin: 0 0 .5em 0;
        -        white-space: nowrap;
        -        }
        -
        -
        -
        -
        -
        -.Summary {
        -    margin: 1.5em 5ex 0 5ex }
        -
        -    .STitle {
        -        font-size: 14pt; font-weight: bold;
        -        margin-bottom: .5em }
        -
        -
        -    .SBorder {
        -        background-color: #FFFFF0;
        -        padding: 15px;
        -        border: 1px solid #C0C060 }
        -
        -    /* In a frame IE 6 will make them too long unless you set the width to 100%.  Without frames it will be correct without a width
        -        or slightly too long (but not enough to scroll) with a width.  This arbitrary weirdness simply astounds me.  IE 7 has the same
        -        problem with frames, haven't tested it without.  */
        -    .FramedContentPage .IE .SBorder {
        -        width: 100% }
        -
        -    /*  A treat for Mozilla users.  Blatantly non-standard.  Will be replaced with CSS 3 attributes when finalized/supported.  */
        -    .Firefox .SBorder {
        -        -moz-border-radius: 20px }
        -
        -
        -    .STable {
        -        font-size: 10pt; width: 100% }
        -
        -    .SEntry {
        -        width: 30% }
        -    .SDescription {
        -        width: 70% }
        -
        -
        -    .SMarked {
        -        background-color: #F8F8D8 }
        -
        -    .SDescription { padding-left: 2ex }
        -    .SIndent1 .SEntry { padding-left: 1.5ex }   .SIndent1 .SDescription { padding-left: 3.5ex }
        -    .SIndent2 .SEntry { padding-left: 3.0ex }   .SIndent2 .SDescription { padding-left: 5.0ex }
        -    .SIndent3 .SEntry { padding-left: 4.5ex }   .SIndent3 .SDescription { padding-left: 6.5ex }
        -    .SIndent4 .SEntry { padding-left: 6.0ex }   .SIndent4 .SDescription { padding-left: 8.0ex }
        -    .SIndent5 .SEntry { padding-left: 7.5ex }   .SIndent5 .SDescription { padding-left: 9.5ex }
        -
        -    .SDescription a { color: #800000}
        -    .SDescription a:active { color: #A00000 }
        -
        -    .SGroup td {
        -        padding-top: .5em; padding-bottom: .25em }
        -
        -    .SGroup .SEntry {
        -        font-weight: bold; font-variant: small-caps }
        -
        -    .SGroup .SEntry a { color: #800000 }
        -    .SGroup .SEntry a:active { color: #F00000 }
        -
        -
        -    .SMain td,
        -    .SClass td,
        -    .SDatabase td,
        -    .SDatabaseTable td,
        -    .SSection td {
        -        font-size: 12pt;
        -        padding-bottom: .25em }
        -
        -    .SClass td,
        -    .SDatabase td,
        -    .SDatabaseTable td,
        -    .SSection td {
        -        padding-top: 1em }
        -
        -    .SMain .SEntry,
        -    .SClass .SEntry,
        -    .SDatabase .SEntry,
        -    .SDatabaseTable .SEntry,
        -    .SSection .SEntry {
        -        font-weight: bold;
        -        }
        -
        -    .SMain .SEntry a,
        -    .SClass .SEntry a,
        -    .SDatabase .SEntry a,
        -    .SDatabaseTable .SEntry a,
        -    .SSection .SEntry a { color: #000000 }
        -
        -    .SMain .SEntry a:active,
        -    .SClass .SEntry a:active,
        -    .SDatabase .SEntry a:active,
        -    .SDatabaseTable .SEntry a:active,
        -    .SSection .SEntry a:active { color: #A00000 }
        -
        -
        -
        -
        -
        -.ClassHierarchy {
        -    margin: 0 15px 1em 15px }
        -
        -    .CHEntry {
        -        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0;
        -        margin-bottom: 3px;
        -        padding: 2px 2ex;
        -        font-size: 12pt;
        -        background-color: #F4F4F4; color: #606060;
        -        }
        -
        -    .Firefox .CHEntry {
        -        -moz-border-radius: 4px;
        -        }
        -
        -    .CHCurrent .CHEntry {
        -        font-weight: bold;
        -        border-color: #000000;
        -        color: #000000;
        -        }
        -
        -    .CHChildNote .CHEntry {
        -        font-style: italic;
        -        font-size: 10pt;
        -        }
        -
        -    .CHIndent {
        -        margin-left: 3ex;
        -        }
        -
        -    .CHEntry a:link,
        -    .CHEntry a:visited,
        -    .CHEntry a:hover {
        -        color: #606060;
        -        }
        -    .CHEntry a:active {
        -        color: #800000;
        -        }
        -
        -
        -
        -
        -
        -#Index {
        -    background-color: #FFFFFF;
        -    }
        -
        -/*  As opposed to .PopupSearchResultsPage #Index  */
        -.IndexPage #Index,
        -.FramedIndexPage #Index,
        -.FramedSearchResultsPage #Index {
        -    padding: 15px;
        -    }
        -
        -.IndexPage #Index {
        -    border-width: 0 0 1px 1px;
        -    border-style: solid;
        -    border-color: #000000;
        -    font-size: 10pt;  /* To make 27ex match the menu's 27ex. */
        -    margin-left: 27ex;
        -    }
        -
        -
        -    .IPageTitle {
        -        font-size: 24pt; font-weight: bold;
        -        color: #FFFFFF; background-color: #7070C0;
        -        padding: 10px 15px 10px 15px;
        -        border-width: 0 0 3px 0; border-color: #000000; border-style: solid;
        -        margin: -15px -15px 0 -15px }
        -
        -    .FramedSearchResultsPage .IPageTitle {
        -        margin-bottom: 15px;
        -        }
        -
        -    .INavigationBar {
        -        text-align: center;
        -        background-color: #FFFFF0;
        -        padding: 5px;
        -        border-bottom: solid 1px black;
        -        margin: 0 -15px 15px -15px;
        -        }
        -
        -    .INavigationBar a {
        -        font-weight: bold }
        -
        -    .IHeading {
        -        font-size: 20pt; font-weight: bold;
        -        padding: 2.5em 0 .5em 0;
        -        text-align: center;
        -        width: 3.5ex;
        -        }
        -    #IFirstHeading {
        -        padding-top: 0;
        -        }
        -
        -    .IEntry {
        -        font-size: 12pt;
        -        padding-left: 1ex;
        -        }
        -    .PopupSearchResultsPage .IEntry {
        -        font-size: 10pt;
        -        padding: 1px 5px;
        -        }
        -    .PopupSearchResultsPage .Opera9 .IEntry,
        -    .FramedSearchResultsPage .Opera9 .IEntry {
        -        text-align: left;
        -        }
        -    .FramedSearchResultsPage .IEntry {
        -        padding: 0;
        -        }
        -
        -    .ISubIndex {
        -        padding-left: 3ex; padding-bottom: .5em }
        -    .PopupSearchResultsPage .ISubIndex {
        -        display: none;
        -        }
        -
        -    /*  While it may cause some entries to look like links when they aren't, I found it's much easier to read the
        -         index if everything's the same color.  */
        -    .ISymbol {
        -        font-weight: bold; color: #900000  }
        -
        -    .IndexPage .ISymbolPrefix,
        -    .FramedIndexPage .ISymbolPrefix {
        -        font-size: 12pt;
        -        text-align: right;
        -        color: #C47C7C;
        -        background-color: #F8F8F8;
        -        border-right: 3px solid #E0E0E0;
        -        border-left: 1px solid #E0E0E0;
        -        padding: 0 1px 0 2px;
        -        }
        -    .PopupSearchResultsPage .ISymbolPrefix,
        -    .FramedSearchResultsPage .ISymbolPrefix {
        -        color: #900000;
        -        }
        -    .PopupSearchResultsPage .ISymbolPrefix {
        -        font-size: 10pt;
        -        }
        -
        -    .IndexPage #IFirstSymbolPrefix,
        -    .FramedIndexPage #IFirstSymbolPrefix {
        -        border-top: 1px solid #E0E0E0;
        -        }
        -    .IndexPage #ILastSymbolPrefix,
        -    .FramedIndexPage #ILastSymbolPrefix {
        -        border-bottom: 1px solid #E0E0E0;
        -        }
        -    .IndexPage #IOnlySymbolPrefix,
        -    .FramedIndexPage #IOnlySymbolPrefix {
        -        border-top: 1px solid #E0E0E0;
        -        border-bottom: 1px solid #E0E0E0;
        -        }
        -
        -    a.IParent,
        -    a.IFile {
        -        display: block;
        -        }
        -
        -    .PopupSearchResultsPage .SRStatus {
        -        padding: 2px 5px;
        -        font-size: 10pt;
        -        font-style: italic;
        -        }
        -    .FramedSearchResultsPage .SRStatus {
        -        font-size: 12pt;
        -        font-style: italic;
        -        }
        -
        -    .SRResult {
        -        display: none;
        -        }
        -
        -
        -
        -#Footer {
        -    font-size: 8pt;
        -    color: #989898;
        -    text-align: right;
        -    }
        -
        -#Footer p {
        -    text-indent: 0;
        -    margin-bottom: .5em;
        -    }
        -
        -.ContentPage #Footer,
        -.IndexPage #Footer {
        -    text-align: right;
        -    margin: 2px;
        -    }
        -
        -.FramedMenuPage #Footer {
        -    text-align: center;
        -    margin: 5em 10px 10px 10px;
        -    padding-top: 1em;
        -    border-top: 1px solid #C8C8C8;
        -    }
        -
        -    #Footer a:link,
        -    #Footer a:hover,
        -    #Footer a:visited { color: #989898 }
        -    #Footer a:active { color: #A00000 }
        -
        -
        -
        -.prettyprint .kwd { color: #800000; }  /* keywords */
        -
        -    .prettyprint.PDefaultValue .kwd,
        -    .prettyprint.PDefaultValuePrefix .kwd,
        -    .prettyprint.PTypePrefix .kwd {
        -        color: #C88F8F;
        -        }
        -
        -.prettyprint .com { color: #008000; }  /* comments */
        -
        -    .prettyprint.PDefaultValue .com,
        -    .prettyprint.PDefaultValuePrefix .com,
        -    .prettyprint.PTypePrefix .com {
        -        color: #8FC88F;
        -        }
        -
        -.prettyprint .str { color: #0000B0; }  /* strings */
        -.prettyprint .lit { color: #0000B0; }  /* literals */
        -
        -    .prettyprint.PDefaultValue .str,
        -    .prettyprint.PDefaultValuePrefix .str,
        -    .prettyprint.PTypePrefix .str,
        -    .prettyprint.PDefaultValue .lit,
        -    .prettyprint.PDefaultValuePrefix .lit,
        -    .prettyprint.PTypePrefix .lit {
        -        color: #8F8FC0;
        -        }
        -
        -.prettyprint .typ { color: #000000; }  /* types */
        -.prettyprint .pun { color: #000000; }  /* punctuation */
        -.prettyprint .pln { color: #000000; }  /* punctuation */
        -
        -    .prettyprint.PDefaultValue .typ,
        -    .prettyprint.PDefaultValuePrefix .typ,
        -    .prettyprint.PTypePrefix .typ,
        -    .prettyprint.PDefaultValue .pun,
        -    .prettyprint.PDefaultValuePrefix .pun,
        -    .prettyprint.PTypePrefix .pun,
        -    .prettyprint.PDefaultValue .pln,
        -    .prettyprint.PDefaultValuePrefix .pln,
        -    .prettyprint.PTypePrefix .pln {
        -        color: #8F8F8F;
        -        }
        -
        -.prettyprint .tag { color: #008; }
        -.prettyprint .atn { color: #606; }
        -.prettyprint .atv { color: #080; }
        -.prettyprint .dec { color: #606; }
        -
        diff --git a/vendor/naturaldocs/Styles/Small.css b/vendor/naturaldocs/Styles/Small.css
        deleted file mode 100644
        index 1832d8f39..000000000
        --- a/vendor/naturaldocs/Styles/Small.css
        +++ /dev/null
        @@ -1,824 +0,0 @@
        -/*
        -   IMPORTANT: If you're editing this file in the output directory of one of
        -   your projects, your changes will be overwritten the next time you run
        -   Natural Docs.  Instead, copy this file to your project directory, make your
        -   changes, and you can use it with -s.  Even better would be to make a CSS
        -   file in your project directory with only your changes, which you can then
        -   use with -s [original style] [your changes].
        -
        -   On the other hand, if you're editing this file in the Natural Docs styles
        -   directory, the changes will automatically be applied to all your projects
        -   that use this style the next time Natural Docs is run on them.
        -
        -   This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure.
        -   Natural Docs is licensed under version 3 of the GNU Affero General Public
        -   License (AGPL).  Refer to License.txt for the complete details.
        -
        -   This file may be distributed with documentation files generated by Natural Docs.
        -   Such documentation is not covered by Natural Docs' copyright and licensing,
        -   and may have its own copyright and distribution terms as decided by its author.
        -*/
        -
        -body {
        -    font: 8pt Verdana, Arial, sans-serif;
        -    color: #000000;
        -    margin: 0; padding: 0;
        -    }
        -
        -.ContentPage,
        -.IndexPage,
        -.FramedMenuPage {
        -    background-color: #E8E8E8;
        -    }
        -.FramedContentPage,
        -.FramedIndexPage,
        -.FramedSearchResultsPage,
        -.PopupSearchResultsPage {
        -    background-color: #FFFFFF;
        -    }
        -
        -
        -a:link,
        -a:visited { color: #900000; text-decoration: none }
        -a:hover { color: #900000; text-decoration: underline }
        -a:active { color: #FF0000; text-decoration: underline }
        -
        -td {
        -    vertical-align: top }
        -
        -img { border: 0;  }
        -
        -
        -/*
        -    Comment out this line to use web-style paragraphs (blank line between
        -    paragraphs, no indent) instead of print-style paragraphs (no blank line,
        -    indented.)
        -*/
        -p {
        -    text-indent: 5ex; margin: 0 }
        -
        -
        -/*  Opera doesn't break with just wbr, but will if you add this.  */
        -.Opera wbr:after {
        -	content: "\00200B";
        -	}
        -
        -/*  Blockquotes are used as containers for things that may need to scroll.  */
        -blockquote {
        -    padding: 0;
        -    margin: 0;
        -    overflow: auto;
        -    }
        -
        -
        -.Firefox1 blockquote {
        -    padding-bottom: .5em;
        -    }
        -
        -/*  Turn off scrolling when printing.  */
        -@media print {
        -    blockquote {
        -        overflow: visible;
        -        }
        -    .IE blockquote {
        -        width: auto;
        -        }
        -    }
        -
        -
        -
        -#Menu {
        -    font-size: 8pt;
        -    padding: 10px 0 0 0;
        -    }
        -.ContentPage #Menu,
        -.IndexPage #Menu {
        -    position: absolute;
        -    top: 0;
        -    left: 0;
        -    width: 31ex;
        -    overflow: hidden;
        -    }
        -.ContentPage .Firefox #Menu,
        -.IndexPage .Firefox #Menu {
        -    width: 27ex;
        -    }
        -
        -
        -    .MTitle {
        -        font-size: 16pt; font-weight: bold; font-variant: small-caps;
        -        text-align: center;
        -        padding: 5px 10px 15px 10px;
        -        border-bottom: 1px dotted #000000;
        -        margin-bottom: 15px }
        -
        -    .MSubTitle {
        -        font-size: 9pt; font-weight: normal; font-variant: normal;
        -        margin-top: 1ex; margin-bottom: 5px }
        -
        -
        -    .MEntry a:link,
        -    .MEntry a:hover,
        -    .MEntry a:visited { color: #606060; margin-right: 0 }
        -    .MEntry a:active { color: #A00000; margin-right: 0 }
        -
        -
        -    .MGroup {
        -        font-variant: small-caps; font-weight: bold;
        -        margin: 1em 0 1em 10px;
        -        }
        -
        -    .MGroupContent {
        -        font-variant: normal; font-weight: normal }
        -
        -    .MGroup a:link,
        -    .MGroup a:hover,
        -    .MGroup a:visited { color: #545454; margin-right: 10px }
        -    .MGroup a:active { color: #A00000; margin-right: 10px }
        -
        -
        -    .MFile,
        -    .MText,
        -    .MLink,
        -    .MIndex {
        -        padding: 1px 17px 2px 10px;
        -        margin: .25em 0 .25em 0;
        -        }
        -
        -    .MText {
        -        font-size: 8pt; font-style: italic }
        -
        -    .MLink {
        -        font-style: italic }
        -
        -    #MSelected {
        -        color: #000000; background-color: #FFFFFF;
        -        /*  Replace padding with border.  */
        -        padding: 0 10px 0 10px;
        -        border-width: 1px 2px 2px 0; border-style: solid; border-color: #000000;
        -        margin-right: 5px;
        -        }
        -
        -    /*  Close off the left side when its in a group.  */
        -    .MGroup #MSelected {
        -        padding-left: 9px; border-left-width: 1px }
        -
        -    /*  A treat for Mozilla users.  Blatantly non-standard.  Will be replaced with CSS 3 attributes when finalized/supported.  */
        -    .Firefox #MSelected {
        -        -moz-border-radius-topright: 10px;
        -        -moz-border-radius-bottomright: 10px }
        -    .Firefox .MGroup #MSelected {
        -        -moz-border-radius-topleft: 10px;
        -        -moz-border-radius-bottomleft: 10px }
        -
        -
        -    #MSearchPanel {
        -        padding: 0px 6px;
        -        margin: .25em 0;
        -        }
        -
        -
        -    #MSearchField {
        -        font: italic 8pt Verdana, sans-serif;
        -        color: #606060;
        -        background-color: #E8E8E8;
        -        border: none;
        -        padding: 2px 4px;
        -        width: 100%;
        -        }
        -    /* Only Opera gets it right. */
        -    .Firefox #MSearchField,
        -    .IE #MSearchField,
        -    .Safari #MSearchField {
        -        width: 94%;
        -        }
        -    .Opera9 #MSearchField,
        -    .Konqueror #MSearchField {
        -        width: 97%;
        -        }
        -    .FramedMenuPage .Firefox #MSearchField,
        -    .FramedMenuPage .Safari #MSearchField,
        -    .FramedMenuPage .Konqueror #MSearchField {
        -        width: 98%;
        -        }
        -
        -    /* Firefox doesn't do this right in frames without #MSearchPanel added on.
        -        It's presence doesn't hurt anything other browsers. */
        -    #MSearchPanel.MSearchPanelInactive:hover #MSearchField {
        -        background-color: #FFFFFF;
        -        border: 1px solid #C0C0C0;
        -        padding: 1px 3px;
        -        }
        -    .MSearchPanelActive #MSearchField {
        -        background-color: #FFFFFF;
        -        border: 1px solid #C0C0C0;
        -        font-style: normal;
        -        padding: 1px 3px;
        -        }
        -
        -    #MSearchType {
        -        visibility: hidden;
        -        font: 8pt Verdana, sans-serif;
        -        width: 98%;
        -        padding: 0;
        -        border: 1px solid #C0C0C0;
        -        }
        -    .MSearchPanelActive #MSearchType,
        -    /*  As mentioned above, Firefox doesn't do this right in frames without #MSearchPanel added on. */
        -    #MSearchPanel.MSearchPanelInactive:hover #MSearchType,
        -    #MSearchType:focus {
        -        visibility: visible;
        -        color: #606060;
        -        }
        -    #MSearchType option#MSearchEverything {
        -        font-weight: bold;
        -        }
        -
        -    .Opera8 .MSearchPanelInactive:hover,
        -    .Opera8 .MSearchPanelActive {
        -        margin-left: -1px;
        -        }
        -
        -
        -    iframe#MSearchResults {
        -        width: 60ex;
        -        height: 15em;
        -        }
        -    #MSearchResultsWindow {
        -        display: none;
        -        position: absolute;
        -        left: 0; top: 0;
        -        border: 1px solid #000000;
        -        background-color: #E8E8E8;
        -        }
        -    #MSearchResultsWindowClose {
        -        font-weight: bold;
        -        font-size: 8pt;
        -        display: block;
        -        padding: 2px 5px;
        -        }
        -    #MSearchResultsWindowClose:link,
        -    #MSearchResultsWindowClose:visited {
        -        color: #000000;
        -        text-decoration: none;
        -        }
        -    #MSearchResultsWindowClose:active,
        -    #MSearchResultsWindowClose:hover {
        -        color: #800000;
        -        text-decoration: none;
        -        background-color: #F4F4F4;
        -        }
        -
        -
        -
        -
        -#Content {
        -    padding-bottom: 15px;
        -    }
        -
        -.ContentPage #Content {
        -    border-width: 0 0 1px 1px;
        -    border-style: solid;
        -    border-color: #000000;
        -    background-color: #FFFFFF;
        -    font-size: 8pt;  /* To make 31ex match the menu's 31ex. */
        -    margin-left: 31ex;
        -    }
        -.ContentPage .Firefox #Content {
        -    margin-left: 27ex;
        -    }
        -
        -
        -
        -    .CTopic {
        -        font-size: 8pt;
        -        margin-bottom: 3em;
        -        }
        -
        -
        -    .CTitle {
        -        font-size: 11pt; font-weight: bold;
        -        border-width: 0 0 1px 0; border-style: solid; border-color: #A0A0A0;
        -        margin: 0 15px .5em 15px }
        -
        -    .CGroup .CTitle {
        -        font-size: 16pt; font-variant: small-caps;
        -        padding-left: 15px; padding-right: 15px;
        -        border-width: 0 0 2px 0; border-color: #000000;
        -        margin-left: 0; margin-right: 0 }
        -
        -    .CClass .CTitle,
        -    .CInterface .CTitle,
        -    .CDatabase .CTitle,
        -    .CDatabaseTable .CTitle,
        -    .CSection .CTitle {
        -        font-size: 18pt;
        -        color: #FFFFFF; background-color: #A0A0A0;
        -        padding: 10px 15px 10px 15px;
        -        border-width: 2px 0; border-color: #000000;
        -        margin-left: 0; margin-right: 0 }
        -
        -    #MainTopic .CTitle {
        -        font-size: 20pt;
        -        color: #FFFFFF; background-color: #7070C0;
        -        padding: 10px 15px 10px 15px;
        -        border-width: 0 0 3px 0; border-color: #000000;
        -        margin-left: 0; margin-right: 0 }
        -
        -    .CBody {
        -        margin-left: 15px; margin-right: 15px }
        -
        -
        -    .CToolTip {
        -        position: absolute; visibility: hidden;
        -        left: 0; top: 0;
        -        background-color: #FFFFE0;
        -        padding: 5px;
        -        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #000000;
        -        font-size: 8pt;
        -        }
        -
        -    .Opera .CToolTip {
        -        max-width: 98%;
        -        }
        -
        -    /*  Scrollbars would be useless.  */
        -    .CToolTip blockquote {
        -        overflow: hidden;
        -        }
        -    .IE6 .CToolTip blockquote {
        -        overflow: visible;
        -        }
        -
        -    .CHeading {
        -        font-weight: bold; font-size: 9pt;
        -        margin: 1.5em 0 .5em 0;
        -        }
        -
        -    .CBody pre {
        -        font: 8pt "Courier New", Courier, monospace;
        -	    background-color: #FCFCFC;
        -	    margin: 1em 35px;
        -	    padding: 10px 15px 10px 10px;
        -	    border-color: #E0E0E0 #E0E0E0 #E0E0E0 #E4E4E4;
        -	    border-width: 1px 1px 1px 6px;
        -	    border-style: dashed dashed dashed solid;
        -        }
        -
        -    .CBody ul {
        -        /*  I don't know why CBody's margin doesn't apply, but it's consistent across browsers so whatever.
        -             Reapply it here as padding.  */
        -        padding-left: 15px; padding-right: 15px;
        -        margin: .5em 5ex .5em 5ex;
        -        }
        -
        -    .CDescriptionList {
        -        margin: .5em 5ex 0 5ex }
        -
        -        .CDLEntry {
        -            font: 8pt "Courier New", Courier, monospace; color: #808080;
        -            padding-bottom: .25em;
        -            white-space: nowrap }
        -
        -        .CDLDescription {
        -            font-size: 8pt;  /*  For browsers that don't inherit correctly, like Opera 5.  */
        -            padding-bottom: .5em; padding-left: 5ex }
        -
        -
        -    .CTopic img {
        -        text-align: center;
        -        display: block;
        -        margin: 1em auto;
        -        }
        -    .CImageCaption {
        -        font-variant: small-caps;
        -        font-size: 8pt;
        -        color: #808080;
        -        text-align: center;
        -        position: relative;
        -        top: 1em;
        -        }
        -
        -    .CImageLink {
        -        color: #808080;
        -        font-style: italic;
        -        }
        -    a.CImageLink:link,
        -    a.CImageLink:visited,
        -    a.CImageLink:hover { color: #808080 }
        -
        -
        -
        -
        -
        -.Prototype {
        -    font: 8pt "Courier New", Courier, monospace;
        -    padding: 5px 3ex;
        -    border-width: 1px; border-style: solid;
        -    margin: 0 5ex 1.5em 5ex;
        -    }
        -
        -    .Prototype td {
        -        font-size: 8pt;
        -        }
        -
        -    .PDefaultValue,
        -    .PDefaultValuePrefix,
        -    .PTypePrefix {
        -        color: #8F8F8F;
        -        }
        -    .PTypePrefix {
        -        text-align: right;
        -        }
        -    .PAfterParameters {
        -        vertical-align: bottom;
        -        }
        -
        -    .IE .Prototype table {
        -        padding: 0;
        -        }
        -
        -    .CFunction .Prototype {
        -        background-color: #F4F4F4; border-color: #D0D0D0 }
        -    .CProperty .Prototype {
        -        background-color: #F4F4FF; border-color: #C0C0E8 }
        -    .CVariable .Prototype {
        -        background-color: #FFFFF0; border-color: #E0E0A0 }
        -
        -    .CClass .Prototype {
        -        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0;
        -        background-color: #F4F4F4;
        -        }
        -    .CInterface .Prototype {
        -        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0D0;
        -        background-color: #F4F4FF;
        -        }
        -
        -    .CDatabaseIndex .Prototype,
        -    .CConstant .Prototype {
        -        background-color: #D0D0D0; border-color: #000000 }
        -    .CType .Prototype,
        -    .CEnumeration .Prototype {
        -        background-color: #FAF0F0; border-color: #E0B0B0;
        -        }
        -    .CDatabaseTrigger .Prototype,
        -    .CEvent .Prototype,
        -    .CDelegate .Prototype {
        -        background-color: #F0FCF0; border-color: #B8E4B8 }
        -
        -    .CToolTip .Prototype {
        -        margin: 0 0 .5em 0;
        -        white-space: nowrap;
        -        }
        -
        -
        -
        -
        -
        -.Summary {
        -    margin: 1.5em 5ex 0 5ex }
        -
        -    .STitle {
        -        font-size: 11pt; font-weight: bold;
        -        margin-bottom: .5em }
        -
        -
        -    .SBorder {
        -        background-color: #FFFFF0;
        -        padding: 15px;
        -        border: 1px solid #C0C060 }
        -
        -    /* In a frame IE 6 will make them too long unless you set the width to 100%.  Without frames it will be correct without a width
        -        or slightly too long (but not enough to scroll) with a width.  This arbitrary weirdness simply astounds me.  IE 7 has the same
        -        problem with frames, haven't tested it without.  */
        -    .FramedContentPage .IE .SBorder {
        -        width: 100% }
        -
        -    /*  A treat for Mozilla users.  Blatantly non-standard.  Will be replaced with CSS 3 attributes when finalized/supported.  */
        -    .Firefox .SBorder {
        -        -moz-border-radius: 20px }
        -
        -
        -    .STable {
        -        font-size: 8pt; width: 100% }
        -
        -    .SEntry {
        -        width: 30% }
        -    .SDescription {
        -        width: 70% }
        -
        -
        -    .SMarked {
        -        background-color: #F8F8D8 }
        -
        -    .SDescription { padding-left: 2ex }
        -    .SIndent1 .SEntry { padding-left: 1.5ex }   .SIndent1 .SDescription { padding-left: 3.5ex }
        -    .SIndent2 .SEntry { padding-left: 3.0ex }   .SIndent2 .SDescription { padding-left: 5.0ex }
        -    .SIndent3 .SEntry { padding-left: 4.5ex }   .SIndent3 .SDescription { padding-left: 6.5ex }
        -    .SIndent4 .SEntry { padding-left: 6.0ex }   .SIndent4 .SDescription { padding-left: 8.0ex }
        -    .SIndent5 .SEntry { padding-left: 7.5ex }   .SIndent5 .SDescription { padding-left: 9.5ex }
        -
        -    .SDescription a { color: #800000}
        -    .SDescription a:active { color: #A00000 }
        -
        -    .SGroup td {
        -        padding-top: .5em; padding-bottom: .25em }
        -
        -    .SGroup .SEntry {
        -        font-weight: bold; font-variant: small-caps }
        -
        -    .SGroup .SEntry a { color: #800000 }
        -    .SGroup .SEntry a:active { color: #F00000 }
        -
        -
        -    .SMain td,
        -    .SClass td,
        -    .SDatabase td,
        -    .SDatabaseTable td,
        -    .SSection td {
        -        font-size: 10pt;
        -        padding-bottom: .25em }
        -
        -    .SClass td,
        -    .SDatabase td,
        -    .SDatabaseTable td,
        -    .SSection td {
        -        padding-top: 1em }
        -
        -    .SMain .SEntry,
        -    .SClass .SEntry,
        -    .SDatabase .SEntry,
        -    .SDatabaseTable .SEntry,
        -    .SSection .SEntry {
        -        font-weight: bold;
        -        }
        -
        -    .SMain .SEntry a,
        -    .SClass .SEntry a,
        -    .SDatabase .SEntry a,
        -    .SDatabaseTable .SEntry a,
        -    .SSection .SEntry a { color: #000000 }
        -
        -    .SMain .SEntry a:active,
        -    .SClass .SEntry a:active,
        -    .SDatabase .SEntry a:active,
        -    .SDatabaseTable .SEntry a:active,
        -    .SSection .SEntry a:active { color: #A00000 }
        -
        -
        -
        -
        -
        -.ClassHierarchy {
        -    margin: 0 15px 1em 15px }
        -
        -    .CHEntry {
        -        border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0;
        -        margin-bottom: 3px;
        -        padding: 2px 2ex;
        -        font-size: 8pt;
        -        background-color: #F4F4F4; color: #606060;
        -        }
        -
        -    .Firefox .CHEntry {
        -        -moz-border-radius: 4px;
        -        }
        -
        -    .CHCurrent .CHEntry {
        -        font-weight: bold;
        -        border-color: #000000;
        -        color: #000000;
        -        }
        -
        -    .CHChildNote .CHEntry {
        -        font-style: italic;
        -        font-size: 8pt;
        -        }
        -
        -    .CHIndent {
        -        margin-left: 3ex;
        -        }
        -
        -    .CHEntry a:link,
        -    .CHEntry a:visited,
        -    .CHEntry a:hover {
        -        color: #606060;
        -        }
        -    .CHEntry a:active {
        -        color: #800000;
        -        }
        -
        -
        -
        -
        -
        -#Index {
        -    background-color: #FFFFFF;
        -    }
        -
        -/*  As opposed to .PopupSearchResultsPage #Index  */
        -.IndexPage #Index,
        -.FramedIndexPage #Index,
        -.FramedSearchResultsPage #Index {
        -    padding: 15px;
        -    }
        -
        -.IndexPage #Index {
        -    border-width: 0 0 1px 1px;
        -    border-style: solid;
        -    border-color: #000000;
        -    font-size: 8pt;  /* To make 27ex match the menu's 27ex. */
        -    margin-left: 27ex;
        -    }
        -
        -
        -    .IPageTitle {
        -        font-size: 20pt; font-weight: bold;
        -        color: #FFFFFF; background-color: #7070C0;
        -        padding: 10px 15px 10px 15px;
        -        border-width: 0 0 3px 0; border-color: #000000; border-style: solid;
        -        margin: -15px -15px 0 -15px }
        -
        -    .FramedSearchResultsPage .IPageTitle {
        -        margin-bottom: 15px;
        -        }
        -
        -    .INavigationBar {
        -        text-align: center;
        -        background-color: #FFFFF0;
        -        padding: 5px;
        -        border-bottom: solid 1px black;
        -        margin: 0 -15px 15px -15px;
        -        }
        -
        -    .INavigationBar a {
        -        font-weight: bold }
        -
        -    .IHeading {
        -        font-size: 14pt; font-weight: bold;
        -        padding: 2.5em 0 .5em 0;
        -        text-align: center;
        -        width: 3.5ex;
        -        }
        -    #IFirstHeading {
        -        padding-top: 0;
        -        }
        -
        -    .IEntry {
        -        padding-left: 1ex;
        -        }
        -    .PopupSearchResultsPage .IEntry {
        -        font-size: 8pt;
        -        padding: 1px 5px;
        -        }
        -    .PopupSearchResultsPage .Opera9 .IEntry,
        -    .FramedSearchResultsPage .Opera9 .IEntry {
        -        text-align: left;
        -        }
        -    .FramedSearchResultsPage .IEntry {
        -        padding: 0;
        -        }
        -
        -    .ISubIndex {
        -        padding-left: 3ex; padding-bottom: .5em }
        -    .PopupSearchResultsPage .ISubIndex {
        -        display: none;
        -        }
        -
        -    /*  While it may cause some entries to look like links when they aren't, I found it's much easier to read the
        -         index if everything's the same color.  */
        -    .ISymbol {
        -        font-weight: bold; color: #900000  }
        -
        -    .IndexPage .ISymbolPrefix,
        -    .FramedIndexPage .ISymbolPrefix {
        -        text-align: right;
        -        color: #C47C7C;
        -        background-color: #F8F8F8;
        -        border-right: 3px solid #E0E0E0;
        -        border-left: 1px solid #E0E0E0;
        -        padding: 0 1px 0 2px;
        -        }
        -    .PopupSearchResultsPage .ISymbolPrefix,
        -    .FramedSearchResultsPage .ISymbolPrefix {
        -        color: #900000;
        -        }
        -    .PopupSearchResultsPage .ISymbolPrefix {
        -        font-size: 8pt;
        -        }
        -
        -    .IndexPage #IFirstSymbolPrefix,
        -    .FramedIndexPage #IFirstSymbolPrefix {
        -        border-top: 1px solid #E0E0E0;
        -        }
        -    .IndexPage #ILastSymbolPrefix,
        -    .FramedIndexPage #ILastSymbolPrefix {
        -        border-bottom: 1px solid #E0E0E0;
        -        }
        -    .IndexPage #IOnlySymbolPrefix,
        -    .FramedIndexPage #IOnlySymbolPrefix {
        -        border-top: 1px solid #E0E0E0;
        -        border-bottom: 1px solid #E0E0E0;
        -        }
        -
        -    a.IParent,
        -    a.IFile {
        -        display: block;
        -        }
        -
        -    .PopupSearchResultsPage .SRStatus {
        -        padding: 2px 5px;
        -        font-size: 8pt;
        -        font-style: italic;
        -        }
        -    .FramedSearchResultsPage .SRStatus {
        -        font-size: 8pt;
        -        font-style: italic;
        -        }
        -
        -    .SRResult {
        -        display: none;
        -        }
        -
        -
        -
        -#Footer {
        -    font-size: 8pt;
        -    color: #989898;
        -    text-align: right;
        -    }
        -
        -#Footer p {
        -    text-indent: 0;
        -    margin-bottom: .5em;
        -    }
        -
        -.ContentPage #Footer,
        -.IndexPage #Footer {
        -    text-align: right;
        -    margin: 2px;
        -    }
        -
        -.FramedMenuPage #Footer {
        -    text-align: center;
        -    margin: 5em 10px 10px 10px;
        -    padding-top: 1em;
        -    border-top: 1px solid #C8C8C8;
        -    }
        -
        -    #Footer a:link,
        -    #Footer a:hover,
        -    #Footer a:visited { color: #989898 }
        -    #Footer a:active { color: #A00000 }
        -
        -
        -
        -.prettyprint .kwd { color: #800000; }  /* keywords */
        -
        -    .prettyprint.PDefaultValue .kwd,
        -    .prettyprint.PDefaultValuePrefix .kwd,
        -    .prettyprint.PTypePrefix .kwd {
        -        color: #C88F8F;
        -        }
        -
        -.prettyprint .com { color: #008000; }  /* comments */
        -
        -    .prettyprint.PDefaultValue .com,
        -    .prettyprint.PDefaultValuePrefix .com,
        -    .prettyprint.PTypePrefix .com {
        -        color: #8FC88F;
        -        }
        -
        -.prettyprint .str { color: #0000B0; }  /* strings */
        -.prettyprint .lit { color: #0000B0; }  /* literals */
        -
        -    .prettyprint.PDefaultValue .str,
        -    .prettyprint.PDefaultValuePrefix .str,
        -    .prettyprint.PTypePrefix .str,
        -    .prettyprint.PDefaultValue .lit,
        -    .prettyprint.PDefaultValuePrefix .lit,
        -    .prettyprint.PTypePrefix .lit {
        -        color: #8F8FC0;
        -        }
        -
        -.prettyprint .typ { color: #000000; }  /* types */
        -.prettyprint .pun { color: #000000; }  /* punctuation */
        -.prettyprint .pln { color: #000000; }  /* punctuation */
        -
        -    .prettyprint.PDefaultValue .typ,
        -    .prettyprint.PDefaultValuePrefix .typ,
        -    .prettyprint.PTypePrefix .typ,
        -    .prettyprint.PDefaultValue .pun,
        -    .prettyprint.PDefaultValuePrefix .pun,
        -    .prettyprint.PTypePrefix .pun,
        -    .prettyprint.PDefaultValue .pln,
        -    .prettyprint.PDefaultValuePrefix .pln,
        -    .prettyprint.PTypePrefix .pln {
        -        color: #8F8F8F;
        -        }
        -
        -.prettyprint .tag { color: #008; }
        -.prettyprint .atn { color: #606; }
        -.prettyprint .atv { color: #080; }
        -.prettyprint .dec { color: #606; }
        -