]> Dogcows Code - chaz/yoink/blobdiff - src/Moof/Script.hh
the massive refactoring effort
[chaz/yoink] / src / Moof / Script.hh
diff --git a/src/Moof/Script.hh b/src/Moof/Script.hh
deleted file mode 100644 (file)
index 974dce7..0000000
+++ /dev/null
@@ -1,1055 +0,0 @@
-
-/*]  Copyright (c) 2009-2010, Charles McGarvey  [**************************
-**]  All rights reserved.
-*
-* vi:ts=4 sw=4 tw=75
-*
-* Distributable under the terms and conditions of the 2-clause BSD license;
-* see the file COPYING for a complete text of the license.
-*
-**************************************************************************/
-
-#ifndef _MOOF_SCRIPT_HH_
-#define _MOOF_SCRIPT_HH_
-
-/**
- * @file Script.hh
- * A thin wrapper over Lua.  This is not meant as a complicated binding
- * package between C++ and Lua.  It is not meant to obscure the division
- * between C++ and Lua but rather to clarify it and make it more
- * manageable.  It does not hide the concept of the Lua stack, but rather
- * provides that mechanism with a certain level of abstraction while also
- * providing a cleaner, more consistent API.
- */
-
-#include <iostream>
-#include <list>
-#include <map>
-#include <string>
-#include <vector>
-
-#include <boost/bind.hpp>
-#include <boost/function.hpp>
-#include <boost/shared_ptr.hpp>
-#include <lua.hpp>
-
-
-namespace Mf {
-
-
-class Script;
-typedef boost::shared_ptr<Script> ScriptP;
-
-
-class Script
-{
-public:
-
-       typedef boost::function<int(Script&)> Function;
-
-       enum Type
-       {
-               NONE                    = LUA_TNONE,
-               NIL                             = LUA_TNIL,
-               BOOLEAN                 = LUA_TBOOLEAN,
-               LIGHTUSERDATA   = LUA_TLIGHTUSERDATA,
-               NUMBER                  = LUA_TNUMBER,
-               STRING                  = LUA_TSTRING,
-               TABLE                   = LUA_TTABLE,
-               FUNCTION                = LUA_TFUNCTION,
-               USERDATA                = LUA_TUSERDATA,
-               THREAD                  = LUA_TTHREAD
-       };
-
-       enum Result
-       {
-               SUCCESS                 = 0,
-               YIELD                   = LUA_YIELD,
-               RUNTIME_ERROR   = LUA_ERRRUN,
-               SYNTAX_ERROR    = LUA_ERRSYNTAX,
-               MEMORY_ERROR    = LUA_ERRMEM,
-               HANDLER_ERROR   = LUA_ERRERR,
-               FILE_ERROR              = LUA_ERRFILE
-       };
-
-       enum PseudoIndex
-       {
-               REGISTRY                = LUA_REGISTRYINDEX,
-               ENVIRONMENT             = LUA_ENVIRONINDEX,
-               GLOBALS                 = LUA_GLOBALSINDEX
-       };
-
-       /**
-        * This is the most prominent abstraction on top of the standard Lua
-        * API.  A Slot object represents a value on the stack.  More
-        * specifically, it represents a position on the stack.  The
-        * distinction is only important when objects are moved around on the
-        * stack or if the Slot represents a negative index on the stack (the
-        * value of which will change as things are pushed onto and popped from
-        * the stack).
-        */
-
-       struct Slot
-       {
-               /**
-                * You have direct access to the index of the value on the stack
-                * being represented.
-                */
-
-               int index;
-
-
-               Slot(const Script& s, int i = 0) :
-                       index(i),
-                       mScript(const_cast<Script&>(s)) {}
-
-               /**
-                * A copied value presently points to the same value, except the
-                * real index is used.  That means that if a value that refers to a
-                * frame referenced from the top of the stack will have its
-                * normalized index copied into the new value object.
-                */
-
-               //Slot(const Slot& copy) :
-                       //index(copy.positiveIndex()),
-                       //mScript(copy.mScript) {}
-
-
-               // check the type of the value
-               bool isBoolean() const
-               { return (bool)lua_isboolean(mScript.mState, index); }
-               bool isImportedFunction() const
-               { return (bool)lua_iscfunction(mScript.mState, index); }
-               bool isFunction() const
-               { return (bool)lua_isfunction(mScript.mState, index); }
-               bool isNil() const
-               { return (bool)lua_isnil(mScript.mState, index); }
-               bool isNone() const
-               { return (bool)lua_isnone(mScript.mState, index); }
-               bool isNoneOrNil() const
-               { return (bool)lua_isnoneornil(mScript.mState, index); }
-               bool isNumber() const
-               { return (bool)lua_isnumber(mScript.mState, index); }
-               bool isString() const
-               { return (bool)lua_isstring(mScript.mState, index); }
-               bool isTable() const
-               { return (bool)lua_istable(mScript.mState, index); }
-               bool isThread() const
-               { return (bool)lua_isthread(mScript.mState, index); }
-               bool isData() const
-               { return (bool)lua_isuserdata(mScript.mState, index); }
-               bool isLightData() const
-               { return (bool)lua_islightuserdata(mScript.mState, index); }
-
-               /**
-                * Check the value and throw an error if its the wrong type.
-                * There's a little caveat: This method never returns because it
-                * does a long jump.  Consequently, constructed C++ objects which
-                * exist on the stack between the current frame and some lua
-                * function will not be destructed.  That's not a problem for
-                * objects that only exist on the stack, but any objects that
-                * allocate memory on the heap (such as containers or strings) will
-                * leak.  Therefore, you should only call this method after
-                * cleaning up such objects.  The best thing to do for defining
-                * functions is to simply check all the parameters at the get-go
-                * before any C++ objects are even constructed.
-                */
-
-               void requireType(Type t) const
-               {
-                       if (t != type())
-                       {
-                               luaL_typerror(mScript.mState, index,
-                                                         lua_typename(mScript.mState, t));
-                       }
-               }
-
-               void raise(const char* error)
-               {
-                       luaL_argerror(mScript.mState, index, error);
-               }
-
-
-               Slot& requireBoolean()
-               {
-                       if (!isBoolean())
-                       {
-                               luaL_typerror(mScript.mState, index, "boolean");
-                       }
-                       return *this;
-               }
-               Slot& requireNumber()
-               {
-                       if (!isNumber())
-                       {
-                               luaL_typerror(mScript.mState, index, "number");
-                       }
-                       return *this;
-               }
-               Slot& requireString()
-               {
-                       if (!isString())
-                       {
-                               luaL_typerror(mScript.mState, index, "string");
-                       }
-                       return *this;
-               }
-               Slot& requireTable()
-               {
-                       if (!isTable())
-                       {
-                               luaL_typerror(mScript.mState, index, "table");
-                       }
-                       return *this;
-               }
-               Slot& requireFunction()
-               {
-                       if (!isFunction())
-                       {
-                               luaL_typerror(mScript.mState, index, "function");
-                       }
-                       return *this;
-               }
-               Slot& requireData()
-               {
-                       if (!isData())
-                       {
-                               luaL_typerror(mScript.mState, index, "data");
-                       }
-                       return *this;
-               }
-               Slot& requireNil()
-               {
-                       if (!isNil())
-                       {
-                               luaL_typerror(mScript.mState, index, "nil");
-                       }
-                       return *this;
-               }
-               Slot& requireThread()
-               {
-                       if (!isThread())
-                       {
-                               luaL_typerror(mScript.mState, index, "thread");
-                       }
-                       return *this;
-               }
-
-
-               /**
-                * Get the type of the value.
-                */
-
-               Type type() const
-               {
-                       return (Type)lua_type(mScript.mState, index);
-               }
-
-               /**
-                * Get the name of the type of the value as a string.
-                */
-
-               std::string typeName() const
-               {
-                       return std::string(luaL_typename(mScript.mState, index));
-               }
-
-
-               /**
-                * Get the length of the value according to the definition given by
-                * Lua.
-                */
-
-               size_t length() const
-               {
-                       return lua_objlen(mScript.mState, index);
-               }
-
-               int positiveIndex() const
-               {
-                       if (index < 0) return index + lua_gettop(mScript.mState) + 1;
-                       else           return index;
-               }
-
-
-               /**
-                * Get a pointer value (for userdata, tables, threads, and
-                * functions).
-                */
-
-               const void* id() const
-               {
-                       return lua_topointer(mScript.mState, index);
-               }
-
-               bool isIdentical(const Slot& rhs) const
-               {
-                       return &mScript == &(rhs.mScript) && index == rhs.index;
-               }
-
-               operator bool () const
-               {
-                       return !isNone();
-               }
-
-
-               bool operator == (const Slot& rhs) const
-               {
-                       return (bool)lua_equal(mScript.mState, index, rhs.index);
-               }
-               bool operator != (const Slot& rhs) const
-               {
-                       return !(*this == rhs);
-               }
-
-               bool operator < (const Slot& rhs) const
-               {
-                       return (bool)lua_lessthan(mScript.mState, index, rhs.index);
-               }
-               bool operator <= (const Slot& rhs) const
-               {
-                       return *this < rhs || *this == rhs;
-               }
-               bool operator > (const Slot& rhs) const
-               {
-                       return !(*this <= rhs);
-               }
-               bool operator >= (const Slot& rhs) const
-               {
-                       return !(*this < rhs);
-               }
-
-
-               /**
-                * Convert the underlying value to a C++ type.
-                */
-
-               template <class T>
-               bool get(T& value) const
-               {
-                       if (isNumber())
-                       {
-                               value = (T)lua_tointeger(mScript.mState, index);
-                               return true;
-                       }
-                       return false;
-               }
-
-               bool get(float& value) const
-               {
-                       if (isNumber())
-                       {
-                               value = (float)lua_tonumber(mScript.mState, index);
-                               return true;
-                       }
-                       return false;
-               }
-               bool get(double& value) const
-               {
-                       if (isNumber())
-                       {
-                               value = (double)lua_tonumber(mScript.mState, index);
-                               return true;
-                       }
-                       return false;
-               }
-
-               bool get(bool& value) const
-               {
-                       if (isBoolean())
-                       {
-                               value = (bool)lua_toboolean(mScript.mState, index);
-                               return true;
-                       }
-                       return false;
-               }
-
-               bool get(const char*& value, size_t& size) const
-               {
-                       if (isString())
-                       {
-                               value = lua_tolstring(mScript.mState, index, &size);
-                               return true;
-                       }
-                       return false;
-               }
-
-               bool get(std::string& value) const
-               {
-                       const char*     str;
-                       size_t          size;
-                       if (get(str, size))
-                       {
-                               value.assign(str, size);
-                               return true;
-                       }
-                       return false;
-               }
-
-               bool get(void*& value) const
-               {
-                       if (isData())
-                       {
-                               value = lua_touserdata(mScript.mState, index);
-                               return true;
-                       }
-                       return false;
-               }
-
-               template <class T>
-               bool get(std::vector<T>& array) const
-               {
-                       if (!isTable()) return false;
-
-                       array.clear();
-
-                       Slot    value = mScript[-1];
-                       int             realIndex = positiveIndex();
-
-                       bool done = false;
-                       for (int i = 1; !done; ++i)
-                       {
-                               lua_rawgeti(mScript.mState, realIndex, i);
-
-                               T v;
-                               if (value.get(v)) array.push_back(v);
-                               else              done = true;
-
-                               mScript.pop();
-                       }
-
-                       return true;
-               }
-
-               template <class T>
-               bool get(std::map<std::string,T>& dictionary) const
-               {
-                       if (!isTable()) return false;
-
-                       dictionary.clear();
-
-                       Slot    key = mScript[-2];
-                       Slot    value = mScript[-1];
-                       int             realIndex = positiveIndex();
-
-                       mScript.pushNil();
-                       while (lua_next(mScript.mState, realIndex) != 0)
-                       {
-                               std::string k;
-                               if (!key.isNumber() && key.get(k))
-                               {
-                                       T v;
-                                       if (value.get(v)) dictionary[k] = v;
-                               }
-                               mScript.pop();
-                       }
-                       mScript.pop();
-
-                       return true;
-               }
-
-               /**
-                * Get the value of a field from the table.
-                */
-
-               template <class T, class V>
-               bool get(T& value, V field) const
-               {
-                       bool ret = pushField(field).get(value);
-                       mScript.pop();
-                       return ret;
-               }
-
-
-               template <class T, class V>
-               void setField(T field, V value)
-               {
-                       mScript.push(field);
-                       mScript.push(value);
-                       setField();
-               }
-
-               void setField()
-               {
-                       lua_settable(mScript.mState, index);
-               }
-
-
-               template <class T>
-               void setField(const std::string& field, T value)
-               {
-                       setField(field.c_str(), value);
-               }
-               template <class T>
-               void setField(const char* field, T value)
-               {
-                       mScript.push(value);
-                       lua_setfield(mScript.mState, index, field);
-               }
-
-
-               /**
-                * This set method, as opposed to the others, sets the value of the
-                * actual slot.  The others set table values.
-                */
-               template <class T>
-               void set(T value)
-               {
-                       mScript.push(value);
-                       replace();
-               }
-
-               void set()
-               {
-                       replace();
-               }
-
-
-               /**
-                * Replace this value with the value at the top of the stack.
-                */
-
-               void replace()
-               {
-                       lua_replace(mScript.mState, index);
-               }
-
-               void remove()
-               {
-                       lua_remove(mScript.mState, index);
-               }
-
-               void pop()
-               {
-                       // removes this slot, taking with it everything above it
-                       mScript.pop(mScript.stackSize() - index + 1);
-               }
-
-               /**
-                * Inserts the top-most value on the stack at position index,
-                * shifting other values as needed.
-                */
-
-               void insertTopHere()
-               {
-                       lua_insert(mScript.mState, index);
-               }
-
-
-               /**
-                * Copy the value and push the copy to the stack.
-                */
-
-               Slot pushCopy() const
-               {
-                       lua_pushvalue(mScript.mState, index);
-                       return mScript.top();
-               }
-               
-               Slot pushMetaTable() const
-               {
-                       lua_getmetatable(mScript.mState, index);
-                       return mScript.top();
-               }
-
-               Slot pushEnvironment() const
-               {
-                       lua_getfenv(mScript.mState, index);
-                       return mScript.top();
-               }
-
-
-               Slot pushField() const
-               {
-                       lua_gettable(mScript.mState, index);
-                       return mScript.top();
-               }
-
-               template <class T>
-               Slot pushField(T index) const
-               {
-                       mScript.push(index);
-                       return pushField();
-               }
-
-               Slot pushField(const std::string& name) const
-               {
-                       return pushField(name.c_str());
-               }
-               Slot pushField(const char* name) const
-               {
-                       lua_getfield(mScript.mState, index, name);
-                       return mScript.top();
-               }
-
-
-               Script& script()
-               {
-                       return mScript;
-               }
-
-               const Script& script() const
-               {
-                       return mScript;
-               }
-
-       private:
-
-               Script& mScript;
-       };
-
-
-       Script() :
-               mState(0)
-       {
-               reset();
-       }
-
-       ~Script()
-       {
-               destroy();
-       }
-
-
-       static ScriptP alloc()
-       {
-               return ScriptP(new Script);
-       }
-
-       void reset()
-       {
-               if (mState) destroy();
-               mState = luaL_newstate();
-               registry().setField("Script_hh_Object", (void*)this);
-       }
-
-
-       void importStandardLibraries()
-       {
-               luaL_openlibs(mState);
-       }
-
-       void importBaseLibrary()
-       {
-               lua_pushcfunction(mState, luaopen_base);
-               push(LUA_COLIBNAME);
-               call(1, 0);
-       }
-
-       void importPackageLibrary()
-       {
-               lua_pushcfunction(mState, luaopen_package);
-               push(LUA_LOADLIBNAME);
-               call(1, 0);
-       }
-
-       void importStringLibrary()
-       {
-               lua_pushcfunction(mState, luaopen_string);
-               push(LUA_STRLIBNAME);
-               call(1, 0);
-       }
-
-       void importTableLibrary()
-       {
-               lua_pushcfunction(mState, luaopen_table);
-               push(LUA_TABLIBNAME);
-               call(1, 0);
-       }
-
-       void importMathLibrary()
-       {
-               lua_pushcfunction(mState, luaopen_math);
-               push(LUA_MATHLIBNAME);
-               call(1, 0);
-       }
-
-       void importIoLibrary()
-       {
-               lua_pushcfunction(mState, luaopen_io);
-               push(LUA_IOLIBNAME);
-               call(1, 0);
-       }
-
-       void importOsLibrary()
-       {
-               lua_pushcfunction(mState, luaopen_os);
-               push(LUA_OSLIBNAME);
-               call(1, 0);
-       }
-
-       void importDebugLibrary()
-       {
-               lua_pushcfunction(mState, luaopen_debug);
-               push(LUA_DBLIBNAME);
-               call(1, 0);
-       }
-
-
-       void importFunction(const std::string& name, const Function& function)
-       {
-               push(function);
-               lua_setglobal(mState, name.c_str());
-       }
-
-       Result doString(const std::string& commands)
-       {
-               return (Result)luaL_dostring(mState, commands.c_str());
-       }
-
-       Result doFile(const std::string& file)
-       {
-               return (Result)luaL_dofile(mState, file.c_str());
-       }
-
-
-       /**
-        * Thread-handling methods.
-        */
-
-       Script pushNewThread()
-       {
-               return Script(mState);
-       }
-
-       void pushThread()
-       {
-               lua_pushthread(mState);
-       }
-
-       Result resume(int nargs)
-       {
-               return (Result)lua_resume(mState, nargs);
-       }
-
-       Result getStatus() const
-       {
-               return (Result)lua_status(mState);
-       }
-
-       int yield(int results)
-       {
-               return lua_yield(mState, results);
-       }
-
-       bool isMainThread() const
-       {
-               return mIsMainThread;
-       }
-
-
-       /**
-        * Throw an error with the value at the top of the stack.  This method
-        * never returns because it does a long jump.  Consequently,
-        * constructed C++ objects  which exist on the stack between the
-        * current frame and some lua function will not be destructed.  That's
-        * not a problem for objects that only exist on the stack, but any
-        * objects that allocate memory on the heap (such as containers or
-        * strings) will leak.  Therefore, you should only call this method
-        * after cleaning up such objects.
-        */
-
-       void raise()
-       {
-               lua_error(mState);
-       }
-
-
-       /**
-        * Get significant values.
-        */
-
-       Slot globals() const
-       {
-               return Slot(*this, GLOBALS);
-       }
-
-       Slot registry() const
-       {
-               return Slot(*this, REGISTRY);
-       }
-
-       Slot environment() const
-       {
-               return Slot(*this, ENVIRONMENT);
-       }
-
-       Slot top() const
-       {
-               return Slot(*this, stackSize());
-       }
-
-       /**
-        * Get the size of the stack; this is also the index of the top-most
-        * value.
-        */
-
-       int stackSize() const
-       {
-               return lua_gettop(mState);
-       }
-
-       void setStackSize(int size)
-       {
-               lua_settop(mState, size);
-       }
-
-       void clearStack()
-       {
-               setStackSize(0);
-       }
-
-
-       /**
-        * Makes sure there is at least extra more places on the stack.
-        * Returns false if space couldn't be created.  Just like with the
-        * regular Lua API, you are responsible to make sure the stack is big
-        * enough to hold whatever you want to push on it.  This is usually
-        * only an issue if you're pushing stuff in a loop.
-        */
-
-       bool checkStack(int extra)
-       {
-               return (bool)lua_checkstack(mState, extra);
-       }
-
-
-       /**
-        * Concatenates the top-most n slots on the stack.
-        */
-
-       void concatenate(int n = 2)
-       {
-               lua_concat(mState, n);
-       }
-
-
-       /**
-        * Push some values onto the stack.
-        */
-
-       template <class T>
-       Slot push(T value)
-       {
-               lua_pushinteger(mState, lua_Integer(value));
-               return top();
-       }
-
-       Slot push(bool value)
-       {
-               lua_pushboolean(mState, int(value));
-               return top();
-       }
-
-       Slot push(float value)
-       {
-               lua_pushnumber(mState, (lua_Number)value);
-               return top();
-       }
-       Slot push(double value)
-       {
-               lua_pushnumber(mState, (lua_Number)value);
-               return top();
-       }
-
-       Slot push(const std::string& value)
-       {
-               lua_pushlstring(mState, value.c_str(), value.length());
-               return top();
-       }
-       Slot push(const char* value)
-       {
-               lua_pushstring(mState, value);
-               return top();
-       }
-       Slot push(const char* value, size_t length)
-       {
-               lua_pushlstring(mState, value, length);
-               return top();
-       }
-
-       Slot push(const Function& function)
-       {
-               mFunctions.push_back(function);
-               lua_pushlightuserdata(mState, (void*)&mFunctions.back());
-               lua_pushcclosure(mState, dispatchCall, 1);
-               return top();
-       }
-
-       Slot push(void* data)
-       {
-               lua_pushlightuserdata(mState, data);
-               return top();
-       }
-
-       Slot pushNil()
-       {
-               lua_pushnil(mState);
-               return top();
-       }
-
-       Slot pushFromThread(Script& thread, int n)
-       {
-               lua_xmove(thread.mState, mState, n);
-               return top();
-       }
-
-       Slot pushCode(const std::string& file, Result& result)
-       {
-               result = (Result)luaL_loadfile(mState, file.c_str());
-               return top();
-       }
-
-       Slot pushCode(const std::string& name, const char* buffer,
-                                 size_t size, Result& result)
-       {
-               result = (Result)luaL_loadbuffer(mState,
-                                                                                buffer, size, name.c_str());
-               return top();
-       }
-
-       Slot pushNewData(void*& data, size_t size)
-       {
-               data = lua_newuserdata(mState, size);
-               return top();
-       }
-
-       Slot pushNewTable(int narr = 0, int nrec = 0)
-       {
-               lua_createtable(mState, narr, nrec);
-               return top();
-       }
-
-
-       /**
-        * Call a function on the stack.  The correct procedure is to push a
-        * function onto the stack followed by nargs arguments.  This method
-        * will pop them off upon return, leaving up to nresults return values
-        * (default is any number of return values, depending on the callee).
-        */
-
-       Result call(int nargs = 0, int nresults = LUA_MULTRET)
-       {
-               return (Result)lua_pcall(mState, nargs, nresults, 0);
-       }
-
-
-       /**
-        * Pops n values from the top of the stack.
-        */
-
-       void pop(int n = 1)
-       {
-               lua_pop(mState, n);
-       }
-
-
-       /**
-        * Index into the stack to get a Slot.
-        */
-
-       Slot operator [] (int index) const
-       {
-               return Slot(*this, index);
-       }
-
-
-       /**
-        * Control over the garbage collection process.
-        */
-
-       void collectAll()
-       {
-               lua_gc(mState, LUA_GCCOLLECT, 0);
-       }
-
-       void stopCollector()
-       {
-               lua_gc(mState, LUA_GCSTOP, 0);
-       }
-
-       void restartCollector()
-       {
-               lua_gc(mState, LUA_GCRESTART, 0);
-       }
-
-       int getUsedMemory() const
-       {
-               // in kilobytes
-               return lua_gc(mState, LUA_GCCOUNT, 0);
-       }
-
-       void collectStep(int step)
-       {
-               lua_gc(mState, LUA_GCSTEP, step);
-       }
-
-       void tuneCollector(int pause, int step)
-       {
-               lua_gc(mState, LUA_GCSETPAUSE, pause);
-               lua_gc(mState, LUA_GCSETSTEPMUL, step);
-       }
-
-
-private:
-
-       Script(lua_State* state) :
-               mState(lua_newthread(state)),
-               mIsMainThread(false) {}
-
-       static int dispatchCall(lua_State* state)
-       {
-               const Function* function = (const Function*)lua_touserdata(state,
-                               lua_upvalueindex(1));
-
-               lua_getfield(state, LUA_REGISTRYINDEX, "Script_hh_Object");
-               Script* script = (Script*)lua_touserdata(state, -1);
-               lua_pop(state, 1);
-
-               return (*function)(*script);
-       }
-
-       void destroy()
-       {
-               if (mIsMainThread) lua_close(mState);
-       }
-
-       lua_State*                      mState;
-       bool                            mIsMainThread;
-       std::list<Function>     mFunctions;
-};
-
-
-inline std::ostream& operator << (std::ostream& stream,
-               const Script::Slot& slot)
-{
-       if (slot.isString())
-       {
-               std::string str;
-               slot.get(str);
-               stream << str;
-       }
-       else if (slot.isBoolean())
-       {
-               bool value;
-               slot.get(value);
-               if (value) stream << "true";
-               else       stream << "false";
-       }
-       else if (slot.isNil())
-       {
-               stream << "nil";
-       }
-       else
-       {
-               stream << slot.typeName() << " (" << slot.id() << ")";
-       }
-
-       return stream;
-}
-
-
-} // namespace Mf
-
-#endif // _MOOF_SCRIPT_HH_
-
This page took 0.036048 seconds and 4 git commands to generate.