<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.secondlife.com/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Bushing+Spatula</id>
	<title>Second Life Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.secondlife.com/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Bushing+Spatula"/>
	<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/wiki/Special:Contributions/Bushing_Spatula"/>
	<updated>2026-05-10T11:41:22Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.42.1</generator>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=SLDev_Resident_Names&amp;diff=38748</id>
		<title>SLDev Resident Names</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=SLDev_Resident_Names&amp;diff=38748"/>
		<updated>2007-11-01T05:13:03Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: (don&amp;#039;t ask...)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[SLDev]] &amp;gt; &#039;&#039;&#039;SLDev Resident Names&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Most things associated with Second Life development (in-world meetings, wiki editing, JIRA) are done using Second Life names, but posting on the mailing list is often done using another name (real name or non-Second Life alias).  This page is intended as a decoder ring for people to figure out who&#039;s who on the [[SLDev]] mailing list.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t reveal any information you don&#039;t want to, but if you post messages to the SLDev mailing list under a different name than your Second Life Resident name, please consider dropping your name in the table. (Tip:  putting three tildes, e.g. &amp;quot;&amp;lt;nowiki&amp;gt;~~~&amp;lt;/nowiki&amp;gt;&amp;quot;, will automatically convert to your name and a link to your username on this wiki) :&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; class=sortable&lt;br /&gt;
|-&lt;br /&gt;
!| SLDev Posting Name &lt;br /&gt;
!| Second Life Resident Name&lt;br /&gt;
|-&lt;br /&gt;
| Andre Roche || [[User:Ryozu Kojima|Ryozu Kojima]]&lt;br /&gt;
|-&lt;br /&gt;
| Andy Estes || [[User:Drewan Keats|Drewan Keats]]&lt;br /&gt;
|-&lt;br /&gt;
| Callum Lerwick || [[User:Seg Baphomet|Seg Baphomet]]&lt;br /&gt;
|-&lt;br /&gt;
| Dirk Moerenhout || [[User:Blakar Ogre|Blakar Ogre]]&lt;br /&gt;
|-&lt;br /&gt;
| Dzonatas || [[User:Dzonatas Sol|Dzonatas Sol]]&lt;br /&gt;
|-&lt;br /&gt;
| Ettore Pasquini || [[User:Abstra Apparatchik|Abstra Apparatchik]]&lt;br /&gt;
|-&lt;br /&gt;
| Harold &amp;quot;LabRat&amp;quot; Brown || [[User:Thraxis Epsilon|Thraxis Epsilon]] &lt;br /&gt;
|-&lt;br /&gt;
| Jason Giglio || [[User:Gigs Taggart|Gigs Taggart]]&lt;br /&gt;
|-&lt;br /&gt;
| John Hurliman || [[User:Eddy Stryker|Eddy Stryker]]&lt;br /&gt;
|-&lt;br /&gt;
| Laurent Laborde || [[User:Kerunix Flan|Kerunix Flan]]&lt;br /&gt;
|-&lt;br /&gt;
| Lawson English || [[User:Saijanai Kuhn|Saijanai Kuhn]]&lt;br /&gt;
|-&lt;br /&gt;
| Matt Kimmel || [[User:Feep Larsson|Feep Larsson]]&lt;br /&gt;
|-&lt;br /&gt;
| Mike Monkowski || [[User:Mm Alder|Mm Alder]]&lt;br /&gt;
|-&lt;br /&gt;
| Nik Radford || [[User:Nik Woodget|Nik Woodget]]&lt;br /&gt;
|-&lt;br /&gt;
| Neovo Geesink || [[User:Neovo Geesink|Neovo Geesink]]&lt;br /&gt;
|-&lt;br /&gt;
| Paul Nolan || [[User:Paul Churchill|Paul Churchill]]&lt;br /&gt;
|-&lt;br /&gt;
| Rob Lanphier || [[User:Rob Linden|Rob Linden]] &lt;br /&gt;
|-&lt;br /&gt;
| Ben B yer || [[User:Bushing Spatula|Bushing Spatula]]&lt;br /&gt;
|-&lt;br /&gt;
| Dana Fagerstrom || [[User:Whoops Babii|Whoops Babii]]&lt;br /&gt;
|-&lt;br /&gt;
| Dirk Husemann || [[User:Dr Scofield|Dr Scofield]]&lt;br /&gt;
|-&lt;br /&gt;
| Mark Burhop|| [[User:Burhop Piccard|Burhop Piccard]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Region_feature_requirements&amp;diff=32170</id>
		<title>Region feature requirements</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Region_feature_requirements&amp;diff=32170"/>
		<updated>2007-09-20T05:14:24Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: initial creation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;(Off the top of my head) Here are some features which individual sims may or may not support.  We should decide on which features a compliant sim MUST support, and which it MAY support.&lt;br /&gt;
&lt;br /&gt;
* Physics&lt;br /&gt;
* Portals&lt;br /&gt;
* Building&lt;br /&gt;
* Crossings (from other arbitrary sims)&lt;br /&gt;
* Estate management&lt;br /&gt;
* Money (Lindens, private currency?)&lt;br /&gt;
* Chat&lt;br /&gt;
* Voice&lt;br /&gt;
* Instant Messaging, Intra-Sim&lt;br /&gt;
* Instant Messaging, Inter-Sim&lt;br /&gt;
* Various avatar attributes, such as prim attachments&lt;br /&gt;
* Scripting (LSL, mono?, etc)&lt;br /&gt;
&lt;br /&gt;
Please add your own ideas, and feel free to rearrange this list.&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Workitems_for_Meeting_1&amp;diff=31848</id>
		<title>Workitems for Meeting 1</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Workitems_for_Meeting_1&amp;diff=31848"/>
		<updated>2007-09-17T07:23:05Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: started splitting out subpages&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* WORKITEM: use case librarian (started [[Use Cases|here]])&lt;br /&gt;
* WORKITEM: list possible additional/replacement domains&lt;br /&gt;
* WORKITEM: explore alternative models of decomposition&lt;br /&gt;
* WORKITEM: use cases which expose need for alternative decomposition&lt;br /&gt;
* WORKITEM: design for extension&lt;br /&gt;
* WORKITEM: design for [[Discovering Capabilities]]&lt;br /&gt;
* WORKITEM: how to provide [[streaming input]]&lt;br /&gt;
* WORKITEM: [[URL addressing]] requirements&lt;br /&gt;
* WORKITEM: identify functions by at least by Linden Lab&#039;s use (at least), and cluster as stateful and stateless&lt;br /&gt;
* WORKITEM: list the requirements that the community needs of identity to have the policies it wants&lt;br /&gt;
* WORKITEM: write the [[architectural design]] principles&lt;br /&gt;
* WORKITEM: we need to list a set of agent rights (e.g. being able to leave a region)&lt;br /&gt;
* WORKITEM: what are the feature sets that regions may or may not implement ([[Region feature requirements]])&lt;br /&gt;
* WORKITEM: a list of possible parameters to consider (e.g. region size: should they be something other than 256x256m)&lt;br /&gt;
* WORKITEM: figure out [[vhosting possibilities]] for regions&lt;br /&gt;
* WORKITEM: if there are good use cases for topology changes to the architecture, capture&lt;br /&gt;
* WORKITEM: classify [[modes of content use]] (not exhaustive list of every possible use)&lt;br /&gt;
* WORKITEM: we need a clear definition of what parts of an object are included vs which parts are referential&lt;br /&gt;
* WORKITEM: need to define [[avatar rights on privacy]]&lt;br /&gt;
* WORKITEM: Rob, Zero, Liana will get chat and irc logs posted to sldev; blog post; slides up on wiki... This will take a few days to complete&lt;br /&gt;
* WORKITEM: come back in two weeks with everyone deciding what they can commit to&lt;br /&gt;
* WORKITEM: Mark: post list of messages in the wiki&lt;br /&gt;
&lt;br /&gt;
[[Category:Architecture Working Group]]&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=SLDev_Resident_Names&amp;diff=30915</id>
		<title>SLDev Resident Names</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=SLDev_Resident_Names&amp;diff=30915"/>
		<updated>2007-09-08T17:03:41Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: added meself&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[SLDev]] &amp;gt; &#039;&#039;&#039;SLDev Resident Names&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Most things associated with Second Life development (in-world meetings, wiki editing, JIRA) are done using Second Life names, but posting on the mailing list is often done using another name (real name or non-Second Life alias).  This page is intended as a decoder ring for people to figure out who&#039;s who on the [[SLDev]] mailing list.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t reveal any information you don&#039;t want to, but if you post messages to the SLDev mailing list under a different name than your Second Life Resident name, please consider dropping your name in the table. (Tip:  putting three tildes, e.g. &amp;quot;&amp;lt;nowiki&amp;gt;~~~&amp;lt;/nowiki&amp;gt;&amp;quot;, will automatically convert to your name and a link to your username on this wiki) :&lt;br /&gt;
&lt;br /&gt;
{|border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; class=sortable&lt;br /&gt;
|-&lt;br /&gt;
!| SLDev Posting Name &lt;br /&gt;
!| Second Life Resident Name&lt;br /&gt;
|-&lt;br /&gt;
| Andre Roche || [[User:Ryozu Kojima|Ryozu Kojima]]&lt;br /&gt;
|-&lt;br /&gt;
| Andy Estes || [[User:Drewan Keats|Drewan Keats]]&lt;br /&gt;
|-&lt;br /&gt;
| Callum Lerwick || [[User:Seg Baphomet|Seg Baphomet]]&lt;br /&gt;
|-&lt;br /&gt;
| Dirk Moerenhout || [[User:Blakar Ogre|Blakar Ogre]]&lt;br /&gt;
|-&lt;br /&gt;
| Dzonatas || [[User:Dzonatas Sol|Dzonatas Sol]]&lt;br /&gt;
|-&lt;br /&gt;
| Ettore Pasquini || [[User:Abstra Apparatchik|Abstra Apparatchik]]&lt;br /&gt;
|-&lt;br /&gt;
| Harold &amp;quot;LabRat&amp;quot; Brown || [[User:Thraxis Epsilon|Thraxis Epsilon]] &lt;br /&gt;
|-&lt;br /&gt;
| Jason Giglio || [[User:Gigs Taggart|Gigs Taggart]]&lt;br /&gt;
|-&lt;br /&gt;
| Laurent Laborde || [[User:Kerunix Flan|Kerunix Flan]]&lt;br /&gt;
|-&lt;br /&gt;
| Lawson English || [[User:Saijanai Kuhn|Saijanai Kuhn]]&lt;br /&gt;
|-&lt;br /&gt;
| Matt Kimmel || [[User:Feep Larsson|Feep Larsson]]&lt;br /&gt;
|-&lt;br /&gt;
| Mike Monkowski || [[User:Mm Alder|Mm Alder]]&lt;br /&gt;
|-&lt;br /&gt;
| Nik Radford || [[User:Nik Woodget|Nik Woodget]]&lt;br /&gt;
|-&lt;br /&gt;
| Paul Nolan || [[User:Paul Churchill|Paul Churchill]]&lt;br /&gt;
|-&lt;br /&gt;
| Rob Lanphier || [[User:Rob Linden|Rob Linden]] &lt;br /&gt;
|-&lt;br /&gt;
| Ben Byer || [[User:Bushing Spatula|Bushing Spatula]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Version_control_repository&amp;diff=20967</id>
		<title>Version control repository</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Version_control_repository&amp;diff=20967"/>
		<updated>2007-05-21T05:38:58Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: added OpenGrok link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{CompileNav}}&lt;br /&gt;
&lt;br /&gt;
Linden Lab runs an official Subversion repository that contains occasional snapshots from the internal Linden Lab source repository.  &lt;br /&gt;
&lt;br /&gt;
== Using the repository ==&lt;br /&gt;
&lt;br /&gt;
*  Create a location on your hard drive to check out the code (e.g. Linden Lab developers generally use $HOME/linden)&lt;br /&gt;
*  Select which branch you&#039;d like to check out (see [[Source branches]] for explanation of branches)&lt;br /&gt;
** release: &amp;lt;nowiki&amp;gt;http://svn.secondlife.com/svn/linden/release&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** release-candidate: &amp;lt;nowiki&amp;gt;http://svn.secondlife.com/svn/linden/branches/release-candidate&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** maintenance: &amp;lt;nowiki&amp;gt;http://svn.secondlife.com/svn/linden/branches/maintenance&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** Branch_1-15-0: &amp;lt;nowiki&amp;gt;http://svn.secondlife.com/svn/linden/branches/Branch_1-15-0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** Branch_1-15-1: &amp;lt;nowiki&amp;gt;http://svn.secondlife.com/svn/linden/branches/Branch_1-15-0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** sculpties2: &amp;lt;nowiki&amp;gt;http://svn.secondlife.com/svn/linden/branches/2007/sculpties2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Browse source ==&lt;br /&gt;
&lt;br /&gt;
*  [http://svn.secondlife.com/trac/linden/browser Browse source (using Trac)]&lt;br /&gt;
*  [http://svn.secondlife.com/trac/linden Other tools]&lt;br /&gt;
*  [http://www.openmetaverse.org:8180/source/ Search] and [http://www.openmetaverse.org:8180/source/xref/linden/ browse] source using [http://www.opensolaris.org/os/project/opengrok/ OpenGrok], hosted by OpenMetaverse&lt;br /&gt;
&lt;br /&gt;
== Write access ==&lt;br /&gt;
&lt;br /&gt;
Developers that have signed and submitted [http://secondlife.com/developers/opensource/submitting a contribution agreement] are eligible (not guaranteed) write access to the repository.  Other considerations, such as patches submitted and reasons access is requested will also come into play.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Unofficial repositories ==&lt;br /&gt;
&lt;br /&gt;
Below are repositories maintained by individuals outside Linden Lab.  These repositories are not affiliated with Linden Lab in any way.&lt;br /&gt;
&lt;br /&gt;
=== OpenMetaverse ===&lt;br /&gt;
&lt;br /&gt;
[http://openmetaverse.org OpenMetaverse] hosts an OpenSL project with a public subversion repository.&lt;br /&gt;
&lt;br /&gt;
=== Cafuego ===&lt;br /&gt;
&lt;br /&gt;
[http://au.ubuntu.cafuego.net/dists/edgy-cafuego/secondlife Cafuego&#039;s Edgy Stuff v1.0]&lt;br /&gt;
&lt;br /&gt;
Linux Alpha and Firstlook clients, packaged for Linux Ubuntu Edgy on i386.&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Crash_logs&amp;diff=18331</id>
		<title>Crash logs</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Crash_logs&amp;diff=18331"/>
		<updated>2007-04-25T11:15:12Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: added some info links&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Crash logs are a very important tool for debugging program crashes; they allow a developer to try to fix a bug that they have never personally witnessed.  Second Life automatically submits crash logs to Linden Lab when the viewer crashes, but external developers can&#039;t see them.  If you&#039;d like the broader community to help find the bug that caused Second Life to crash on your computer, you should submit this info as an attachment to the appropriate [[JIRA]] bug.&lt;br /&gt;
&lt;br /&gt;
The exact data you need to send varies on the platform:&lt;br /&gt;
&lt;br /&gt;
* Mac: Please attach two files to the JIRA report&lt;br /&gt;
** the crash log, which will usually be called &amp;quot;Second Life.crash.log&amp;quot;, and will be located in ~/Library/Logs/CrashReporter.  If you&#039;d prefer, you can search Spotlight for &amp;quot;CrashReporter&amp;quot;; it will be one of the Folder matches.  (For a technical discussion of the contents of this file, refer to http://developer.apple.com/technotes/tn2004/tn2123.html)&lt;br /&gt;
** a System Profiler report, which contains all of the necessary data about your computer and the hardware inside of it, so that we may group problems with similar hardware together.  From the Apple menu, go to About This Mac, then click on More Info.  This will open the System Profiler utility; select File -&amp;gt; Save as, pick a name for the file, save it, and then attach it to your JIRA report.  (See also http://developer.apple.com/bugreporter/bugbestpractices.html#SP)&lt;br /&gt;
&lt;br /&gt;
* Windows:&lt;br /&gt;
&lt;br /&gt;
* Linux&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Crash_logs&amp;diff=18330</id>
		<title>Crash logs</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Crash_logs&amp;diff=18330"/>
		<updated>2007-04-25T11:10:05Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: created page about crash logs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Crash logs are a very important tool for debugging program crashes; they allow a developer to try to fix a bug that they have never personally witnessed.  Second Life automatically submits crash logs to Linden Lab when the viewer crashes, but external developers can&#039;t see them.  If you&#039;d like the broader community to help find the bug that caused Second Life to crash on your computer, you should submit this info as an attachment to the appropriate [[JIRA]] bug.&lt;br /&gt;
&lt;br /&gt;
The exact data you need to send varies on the platform:&lt;br /&gt;
&lt;br /&gt;
* Mac: Please attach two files to the JIRA report&lt;br /&gt;
** the crash log, which will usually be called &amp;quot;Second Life.crash.log&amp;quot;, and will be located in ~/Library/Logs/CrashReporter.  If you&#039;d prefer, you can search Spotlight for &amp;quot;CrashReporter&amp;quot;; it will be one of the Folder matches.&lt;br /&gt;
** a System Profiler report, which contains all of the necessary data about your computer and the hardware inside of it, so that we may group problems with similar hardware together.  From the Apple menu, go to About This Mac, then click on More Info.  This will open the System Profiler utility; select File -&amp;gt; Save as, pick a name for the file, save it, and then attach it to your JIRA report.&lt;br /&gt;
&lt;br /&gt;
* Windows:&lt;br /&gt;
&lt;br /&gt;
* Linux&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Hooking_sending_IMs&amp;diff=9907</id>
		<title>Hooking sending IMs</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Hooking_sending_IMs&amp;diff=9907"/>
		<updated>2007-02-13T04:23:36Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; void LLFloaterIMPanel::sendMsg()&lt;br /&gt;
 {&lt;br /&gt;
        LLWString text = mInputEditor-&amp;gt;getWText();&lt;br /&gt;
        LLWString::trim(text);&lt;br /&gt;
        if (!gAgent.isGodlike()&lt;br /&gt;
                &amp;amp;&amp;amp; (mDialog == IM_NOTHING_SPECIAL)&lt;br /&gt;
                &amp;amp;&amp;amp; mOtherParticipantUUID.isNull())&lt;br /&gt;
        {&lt;br /&gt;
                llinfos &amp;lt;&amp;lt; &amp;quot;Cannot send IM to everyone unless you&#039;re a god.&amp;quot; &amp;lt;&amp;lt; llendl;&lt;br /&gt;
                return;&lt;br /&gt;
        }&lt;br /&gt;
        if(text.length() &amp;gt; 0)&lt;br /&gt;
        {&lt;br /&gt;
                // Truncate and convert to UTF8 for transport&lt;br /&gt;
                std::string utf8_text = wstring_to_utf8str(text);&lt;br /&gt;
                utf8_text = utf8str_truncate(utf8_text, MAX_MSG_BUF_SIZE - 1);&lt;br /&gt;
                std::string name;&lt;br /&gt;
                gAgent.buildFullname(name);&lt;br /&gt;
&lt;br /&gt;
                PLUGIN_HOOK(&amp;quot;LLFloaterIMPanel::sendMsg&amp;quot;, &amp;amp;utf8_text, &amp;amp;mOtherParticipantUUID);&lt;br /&gt;
&lt;br /&gt;
                const LLRelationship* info = NULL;&lt;br /&gt;
                info = LLAvatarTracker::instance().getBuddyInfo(mOtherParticipantUUID);&lt;br /&gt;
                U8 offline = (!info || info-&amp;gt;isOnline()) ? IM_ONLINE : IM_OFFLINE;&lt;br /&gt;
&lt;br /&gt;
      [...]&lt;br /&gt;
&lt;br /&gt;
 bool otr_impanel_hook(void *data1, void *data2) {&lt;br /&gt;
        fprintf(stderr, &amp;quot;otr_impanel_hook(%p, %p)\n&amp;quot;, data1, data2);&lt;br /&gt;
        std::string *str=(std::string *)data1;&lt;br /&gt;
        // send OTR whitespace data tag&lt;br /&gt;
        str-&amp;gt;append(OTRL_MESSAGE_TAG_BASE);&lt;br /&gt;
        str-&amp;gt;append(OTRL_MESSAGE_TAG_V2);&lt;br /&gt;
        &lt;br /&gt;
        LLUUID *uuid=(LLUUID *) data2;&lt;br /&gt;
        char uuidbuf[40];&lt;br /&gt;
        uuid-&amp;gt;toString(uuidbuf);&lt;br /&gt;
        fprintf(stderr, &amp;quot; %s to %s&amp;quot;, str-&amp;gt;c_str(), uuidbuf);&lt;br /&gt;
        floater_printf(&amp;quot;Sent OTR whitespace tag to %s\n&amp;quot;, uuidbuf);&lt;br /&gt;
        return TRUE;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Plugin_architecture_Low-level_Architecture&amp;diff=9906</id>
		<title>Plugin architecture Low-level Architecture</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Plugin_architecture_Low-level_Architecture&amp;diff=9906"/>
		<updated>2007-02-13T04:21:42Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: /* Calls from viewer to plugin (hooks) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The three technical challenges for creating a plugin architecture are as follows:&lt;br /&gt;
&lt;br /&gt;
== Code loading ==&lt;br /&gt;
Dynamic loading of natively-compiled executable code can be accomplished with dlopen / dlsym in Linux and MacOSX and LoadLibrary on Win32.&lt;br /&gt;
&lt;br /&gt;
[[dlopen code example]]&lt;br /&gt;
&lt;br /&gt;
== Calls from viewer to plugin (hooks) ==&lt;br /&gt;
&lt;br /&gt;
In order to override or enhance existing functionality in the viewer, we need to be able to replace some code with our own.  One way to do this would be to install &amp;quot;hooks&amp;quot; into commonly-used functions.  In the example implementation code below, you can hook any function by adding &#039;PLUGIN_HOOK(&amp;quot;function_name&amp;quot;, data1, data2)&#039; to the top of the function.&lt;br /&gt;
&lt;br /&gt;
When that macro is called, it looks to see if any hooks have been registered with a name that matches &amp;quot;function_name&amp;quot;.  If so, it executes each one in turn.&lt;br /&gt;
&lt;br /&gt;
Each hook function can affect program execution in one of three ways:&lt;br /&gt;
&lt;br /&gt;
* Pass event through -- a function might decide to ignore this hook based on the contents of data1 and data2, or it might do something which doesn&#039;t disrupt the program flow (such as adding data to an internal list for later use, or displaying a dialog box).  In this case, it should just return TRUE.&lt;br /&gt;
* Modify params, pass event through -- as above, except the hook function can modify the contents of data1 and/or data2 before returning TRUE&lt;br /&gt;
* Swallow event:  Sometimes, we want to completely override the function being hooked, for various reasons -- in this case, the plugin should return FALSE.&lt;br /&gt;
&lt;br /&gt;
PLUGIN_HOOK executes each function in turn; if it function returns FALSE, it just issues a &#039;return&#039; in the context of the hooked function.  If all hooks return TRUE, control will eventually be passed to the hooked function.&lt;br /&gt;
&lt;br /&gt;
[[hook example code]]&lt;br /&gt;
&lt;br /&gt;
[[hooking sending IMs]]&lt;br /&gt;
&lt;br /&gt;
== Calls from plugin to viewer (exposing an API) ==&lt;br /&gt;
&lt;br /&gt;
Most plugins will want to call into the client and have it do things like display dialog boxes, send IMs, etc.  Unfortunately, there&#039;s no simple way to do this.&lt;br /&gt;
&lt;br /&gt;
Ideally, most interesting functions in the viewer would be broken out into dylibs / dlls so that plugins could link against them.  This probably isn&#039;t practical.&lt;br /&gt;
&lt;br /&gt;
The alternate solution is to pick a number of useful functions, build a function pointer table, and allow plugins to ask for them by name.&lt;br /&gt;
&lt;br /&gt;
[[function pointer example code]]&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Function_pointer_example_code&amp;diff=9888</id>
		<title>Function pointer example code</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Function_pointer_example_code&amp;diff=9888"/>
		<updated>2007-02-13T03:33:30Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; class viewer_func  {&lt;br /&gt;
 public:&lt;br /&gt;
        const char * name;&lt;br /&gt;
        func_ptr ptr;&lt;br /&gt;
        viewer_func() {}&lt;br /&gt;
        viewer_func(const char * n, func_ptr p) { name=n; ptr=p;}&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 class plugin_interface {&lt;br /&gt;
 private:&lt;br /&gt;
        hook * get_hook_by_name(const char *name);&lt;br /&gt;
         viewer_func * get_viewer_func_by_name(const char *name);&lt;br /&gt;
 public:&lt;br /&gt;
        LLDynamicArray&amp;lt;hook&amp;gt; hooks;&lt;br /&gt;
        LLDynamicArray&amp;lt;viewer_func&amp;gt; viewer_funcs;&lt;br /&gt;
        &lt;br /&gt;
        void add_hook(const char *name, const func_ptr ptr);  &lt;br /&gt;
 &lt;br /&gt;
       void add_viewer_func(const char *name, func_ptr ptr);&lt;br /&gt;
       char ** get_viewer_func_list();&lt;br /&gt;
       char ** get_hook_list();&lt;br /&gt;
       &lt;br /&gt;
       const char * get_interface_version();&lt;br /&gt;
       void * call_viewer_func(const char *name, void *data1, void *data2);&lt;br /&gt;
       bool call_hooks(const char *name, void *data1, void *data2);&lt;br /&gt;
       void init();&lt;br /&gt;
       //plugin_interface();   &lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
 void plugin_interface::add_viewer_func(const char *name, func_ptr ptr) {&lt;br /&gt;
        /* This should be called upon instantiation several times, once for&lt;br /&gt;
           each internal viewer function we wish to expose to the plugins */&lt;br /&gt;
        viewer_funcs.put(*(new viewer_func(name, ptr)));&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 viewer_func * plugin_interface::get_viewer_func_by_name(const char *name) {&lt;br /&gt;
         // this should really be a hash table lookup&lt;br /&gt;
        for(int i=0; i &amp;lt; viewer_funcs.count() ; i++) &lt;br /&gt;
                if (!strcasecmp(name, viewer_funcs[i].name)) &lt;br /&gt;
                        return &amp;amp;viewer_funcs[i];&lt;br /&gt;
        return NULL;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void * plugin_interface::call_viewer_func(const char *name, void *data1, void *data2) {&lt;br /&gt;
         viewer_func * func = get_viewer_func_by_name(name);&lt;br /&gt;
         fprintf(stderr, &amp;quot;Calling &#039;%s&#039; @ %p\n&amp;quot;, name, func);&lt;br /&gt;
         if (func) return (void *)(func-&amp;gt;ptr)(data1, data2);&lt;br /&gt;
         else return NULL;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Function_pointer_example_code&amp;diff=9887</id>
		<title>Function pointer example code</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Function_pointer_example_code&amp;diff=9887"/>
		<updated>2007-02-13T03:33:09Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; class viewer_func  {&lt;br /&gt;
 public:&lt;br /&gt;
        const char * name;&lt;br /&gt;
        func_ptr ptr;&lt;br /&gt;
        viewer_func() {}&lt;br /&gt;
        viewer_func(const char * n, func_ptr p) { name=n; ptr=p;}&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 class plugin_interface {&lt;br /&gt;
 private:&lt;br /&gt;
        hook * get_hook_by_name(const char *name);&lt;br /&gt;
         viewer_func * get_viewer_func_by_name(const char *name);&lt;br /&gt;
 public:&lt;br /&gt;
        LLDynamicArray&amp;lt;hook&amp;gt; hooks;&lt;br /&gt;
        LLDynamicArray&amp;lt;viewer_func&amp;gt; viewer_funcs;&lt;br /&gt;
        &lt;br /&gt;
        void add_hook(const char *name, const func_ptr ptr);  &lt;br /&gt;
&lt;br /&gt;
       void add_viewer_func(const char *name, func_ptr ptr);&lt;br /&gt;
       char ** get_viewer_func_list();&lt;br /&gt;
       char ** get_hook_list();&lt;br /&gt;
       &lt;br /&gt;
       const char * get_interface_version();&lt;br /&gt;
       void * call_viewer_func(const char *name, void *data1, void *data2);&lt;br /&gt;
       bool call_hooks(const char *name, void *data1, void *data2);&lt;br /&gt;
       void init();&lt;br /&gt;
       //plugin_interface();   &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
 void plugin_interface::add_viewer_func(const char *name, func_ptr ptr) {&lt;br /&gt;
        /* This should be called upon instantiation several times, once for&lt;br /&gt;
           each internal viewer function we wish to expose to the plugins */&lt;br /&gt;
        viewer_funcs.put(*(new viewer_func(name, ptr)));&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 viewer_func * plugin_interface::get_viewer_func_by_name(const char *name) {&lt;br /&gt;
         // this should really be a hash table lookup&lt;br /&gt;
        for(int i=0; i &amp;lt; viewer_funcs.count() ; i++) &lt;br /&gt;
                if (!strcasecmp(name, viewer_funcs[i].name)) &lt;br /&gt;
                        return &amp;amp;viewer_funcs[i];&lt;br /&gt;
        return NULL;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 void * plugin_interface::call_viewer_func(const char *name, void *data1, void *data2) {&lt;br /&gt;
         viewer_func * func = get_viewer_func_by_name(name);&lt;br /&gt;
         fprintf(stderr, &amp;quot;Calling &#039;%s&#039; @ %p\n&amp;quot;, name, func);&lt;br /&gt;
         if (func) return (void *)(func-&amp;gt;ptr)(data1, data2);&lt;br /&gt;
         else return NULL;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Hook_example_code&amp;diff=9885</id>
		<title>Hook example code</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Hook_example_code&amp;diff=9885"/>
		<updated>2007-02-13T03:29:04Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; #include &amp;quot;lldarray.h&amp;quot;&lt;br /&gt;
 // data1 and data2 may be used for any arbitrary user data.&lt;br /&gt;
 // from_plugin should be set to FALSE if the function is being called due to a user&#039;s action,&lt;br /&gt;
 // and TRUE if it is being called from another plugin.  (The idea is to avoid event loops, but&lt;br /&gt;
 // maybe there is a better way.&lt;br /&gt;
 // If function pointer returns FALSE, and this is one of a series of callbacks for a hook, &lt;br /&gt;
 // the function should terminate without passing control to any further plugins or to the&lt;br /&gt;
 // rest of the viewer function.  (This is to allow hook functions to &amp;quot;swallow&amp;quot; events by return FALSE.)&lt;br /&gt;
 typedef bool (*func_ptr)(void *data1, void *data2);&lt;br /&gt;
 &lt;br /&gt;
 class hook {&lt;br /&gt;
 public:&lt;br /&gt;
         const char * name;&lt;br /&gt;
         LLDynamicArray&amp;lt;func_ptr&amp;gt; *hook_ptrs;&lt;br /&gt;
         hook() {}&lt;br /&gt;
         hook(const char *n) {name = n; hook_ptrs = new (LLDynamicArray&amp;lt;func_ptr&amp;gt;)();}&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 class viewer_func  {&lt;br /&gt;
 public:&lt;br /&gt;
         const char * name;&lt;br /&gt;
         func_ptr ptr;&lt;br /&gt;
         viewer_func() {}&lt;br /&gt;
         viewer_func(const char * n, func_ptr p) { name=n; ptr=p;}&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 class plugin_interface {&lt;br /&gt;
 private:&lt;br /&gt;
         hook * get_hook_by_name(const char *name);&lt;br /&gt;
         viewer_func * get_viewer_func_by_name(const char *name);&lt;br /&gt;
 public:&lt;br /&gt;
         LLDynamicArray&amp;lt;hook&amp;gt; hooks;&lt;br /&gt;
         LLDynamicArray&amp;lt;viewer_func&amp;gt; viewer_funcs;&lt;br /&gt;
         &lt;br /&gt;
         void add_hook(const char *name, const func_ptr ptr);  &lt;br /&gt;
 &lt;br /&gt;
        void add_viewer_func(const char *name, func_ptr ptr);&lt;br /&gt;
        char ** get_viewer_func_list();&lt;br /&gt;
        char ** get_hook_list();&lt;br /&gt;
        &lt;br /&gt;
        const char * get_interface_version();&lt;br /&gt;
        void * call_viewer_func(const char *name, void *data1, void *data2);&lt;br /&gt;
        bool call_hooks(const char *name, void *data1, void *data2);&lt;br /&gt;
        void init();&lt;br /&gt;
        //plugin_interface();   &lt;br /&gt;
        &lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 #define PLUGIN_HOOK(name, data1, data2) fprintf(stderr, &amp;quot;PLUGIN_HOOK(%s)\n&amp;quot;, name); if(!gPluginInterface.call_hooks(name, (void *)(data1), (void *)(data2))) return; &lt;br /&gt;
 &lt;br /&gt;
 extern plugin_interface gPluginInterface;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 void plugin_interface::add_hook(const char *name, const func_ptr ptr) {&lt;br /&gt;
        /* This function adds a named hook definition with nothing to call to the list.&lt;br /&gt;
          It should be called once for each hooked function upon instantiation of &lt;br /&gt;
          the plugin interface; the hook_ptrs lists will be filled in, if necessary,&lt;br /&gt;
          by plugin init functions.  We need a list of hook names (function names)&lt;br /&gt;
          so that plugins can ask the interface what hooks it will export. */&lt;br /&gt;
        fprintf(stderr, &amp;quot;add_hook(%s = %p)\n&amp;quot;, name, ptr);&lt;br /&gt;
        if(ptr) {&lt;br /&gt;
                hook * myhook = get_hook_by_name(name);&lt;br /&gt;
                if (myhook == NULL) {&lt;br /&gt;
                        fprintf(stderr, &amp;quot;ERROR: tried to add function to unknown hook %s\n&amp;quot;, name);&lt;br /&gt;
                        return;&lt;br /&gt;
                } &lt;br /&gt;
                myhook-&amp;gt;hook_ptrs-&amp;gt;put(ptr);&lt;br /&gt;
        } else&lt;br /&gt;
                hooks.put(*(new hook(name)));&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 hook * plugin_interface::get_hook_by_name(const char *name) {&lt;br /&gt;
        // this should really be a hash table lookup&lt;br /&gt;
        for(int i=0; i &amp;lt; hooks.count() ; i++) &lt;br /&gt;
                if (!strcasecmp(name, hooks[i].name)) &lt;br /&gt;
                        return &amp;amp;hooks[i];&lt;br /&gt;
        return NULL;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 bool plugin_interface::call_hooks(const char *name, void *data1, void *data2) {&lt;br /&gt;
        hook * func = get_hook_by_name(name);&lt;br /&gt;
        if (func) {&lt;br /&gt;
                for (int i=0; i &amp;lt; func-&amp;gt;hook_ptrs-&amp;gt;count(); i++) {&lt;br /&gt;
                        LLDynamicArray&amp;lt;func_ptr&amp;gt; *fptr_array=func-&amp;gt;hook_ptrs;&lt;br /&gt;
                        func_ptr fptr=(*fptr_array)[i];&lt;br /&gt;
                        if (!(fptr)(data1, data2)) return FALSE;&lt;br /&gt;
                }&lt;br /&gt;
                return TRUE;&lt;br /&gt;
        } else return FALSE;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Hook_example_code&amp;diff=9883</id>
		<title>Hook example code</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Hook_example_code&amp;diff=9883"/>
		<updated>2007-02-13T03:24:19Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; #include &amp;quot;lldarray.h&amp;quot;&lt;br /&gt;
 // data1 and data2 may be used for any arbitrary user data.&lt;br /&gt;
 // from_plugin should be set to FALSE if the function is being called due to a user&#039;s action,&lt;br /&gt;
 // and TRUE if it is being called from another plugin.  (The idea is to avoid event loops, but&lt;br /&gt;
 // maybe there is a better way.&lt;br /&gt;
 // If function pointer returns FALSE, and this is one of a series of callbacks for a hook, &lt;br /&gt;
 // the function should terminate without passing control to any further plugins or to the&lt;br /&gt;
 // rest of the viewer function.  (This is to allow hook functions to &amp;quot;swallow&amp;quot; events by return FALSE.)&lt;br /&gt;
 typedef bool (*func_ptr)(void *data1, void *data2);&lt;br /&gt;
 &lt;br /&gt;
 class hook {&lt;br /&gt;
 public:&lt;br /&gt;
         const char * name;&lt;br /&gt;
         LLDynamicArray&amp;lt;func_ptr&amp;gt; *hook_ptrs;&lt;br /&gt;
         hook() {}&lt;br /&gt;
         hook(const char *n) {name = n; hook_ptrs = new (LLDynamicArray&amp;lt;func_ptr&amp;gt;)();}&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 class viewer_func  {&lt;br /&gt;
 public:&lt;br /&gt;
         const char * name;&lt;br /&gt;
         func_ptr ptr;&lt;br /&gt;
         viewer_func() {}&lt;br /&gt;
         viewer_func(const char * n, func_ptr p) { name=n; ptr=p;}&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 class plugin_interface {&lt;br /&gt;
 private:&lt;br /&gt;
         hook * get_hook_by_name(const char *name);&lt;br /&gt;
         viewer_func * get_viewer_func_by_name(const char *name);&lt;br /&gt;
 public:&lt;br /&gt;
         LLDynamicArray&amp;lt;hook&amp;gt; hooks;&lt;br /&gt;
         LLDynamicArray&amp;lt;viewer_func&amp;gt; viewer_funcs;&lt;br /&gt;
         &lt;br /&gt;
         void add_hook(const char *name, const func_ptr ptr);  &lt;br /&gt;
 &lt;br /&gt;
        void add_viewer_func(const char *name, func_ptr ptr);&lt;br /&gt;
        char ** get_viewer_func_list();&lt;br /&gt;
        char ** get_hook_list();&lt;br /&gt;
        &lt;br /&gt;
        const char * get_interface_version();&lt;br /&gt;
        void * call_viewer_func(const char *name, void *data1, void *data2);&lt;br /&gt;
        bool call_hooks(const char *name, void *data1, void *data2);&lt;br /&gt;
        void init();&lt;br /&gt;
        //plugin_interface();   &lt;br /&gt;
        &lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 #define PLUGIN_HOOK(name, data1, data2) fprintf(stderr, &amp;quot;PLUGIN_HOOK(%s)\n&amp;quot;, name); if(!gPluginInterface.call_hooks(name, (void *)(data1), (void *)(data2))) return; &lt;br /&gt;
 &lt;br /&gt;
 extern plugin_interface gPluginInterface;&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Dlopen_code_example&amp;diff=9882</id>
		<title>Dlopen code example</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Dlopen_code_example&amp;diff=9882"/>
		<updated>2007-02-13T03:22:05Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; void loadPlugins( const char *path ) {&lt;br /&gt;
 #ifndef LL_WINDOWS&lt;br /&gt;
        int (*slp_plugin_init)(plugin_interface *);&lt;br /&gt;
        &lt;br /&gt;
        DIR * plugindir;&lt;br /&gt;
        struct dirent * mydirent;&lt;br /&gt;
        void * dlhandle;&lt;br /&gt;
        char plugin_name[FILENAME_MAX];&lt;br /&gt;
        &lt;br /&gt;
        plugindir = opendir( path );&lt;br /&gt;
    if( NULL == plugindir ) {&lt;br /&gt;
                llwarns &amp;lt;&amp;lt; &amp;quot;Could not open plugins directory: &amp;quot; &amp;lt;&amp;lt; path &amp;lt;&amp;lt; llendl;&lt;br /&gt;
                return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        while (mydirent = readdir(plugindir)) {&lt;br /&gt;
                if(!strcasestr(mydirent-&amp;gt;d_name, PLUGINEXT)) {&lt;br /&gt;
                        fprintf(stderr, &amp;quot;Ignoring non-plugin directory entry %s\n&amp;quot;, mydirent-&amp;gt;d_name);&lt;br /&gt;
                        continue;&lt;br /&gt;
                }&lt;br /&gt;
                &lt;br /&gt;
                snprintf(plugin_name, sizeof(plugin_name), &amp;quot;%s%s%s&amp;quot;, path, gDirUtilp-&amp;gt;getDirDelimiter().c_str(), mydirent-&amp;gt;d_name);&lt;br /&gt;
                fprintf(stderr, &amp;quot;Trying to load plugin: %s\n&amp;quot;, plugin_name);&lt;br /&gt;
                dlhandle = dlopen(plugin_name, RTLD_LAZY);&lt;br /&gt;
                if (dlhandle==NULL) {&lt;br /&gt;
                        fprintf(stderr,&amp;quot;Error opening %s:  %s\n&amp;quot;, plugin_name, dlerror());&lt;br /&gt;
                        continue;&lt;br /&gt;
                }&lt;br /&gt;
                &lt;br /&gt;
                slp_plugin_init = (int(*)(plugin_interface*))dlsym(dlhandle, &amp;quot;initOSLPlugin&amp;quot;);&lt;br /&gt;
                if (!slp_plugin_init) {&lt;br /&gt;
                        fprintf(stderr,&amp;quot;Error looking up initOSLPlugin:  %s\n&amp;quot;, dlerror());&lt;br /&gt;
                        dlclose(dlhandle);&lt;br /&gt;
                        continue;&lt;br /&gt;
                }&lt;br /&gt;
                slp_plugin_init(&amp;amp;gPluginInterface);&lt;br /&gt;
                //char * (*getName)(void) = (char *(*)())dlsym(*(itPlugins), &amp;quot;getPluginName&amp;quot; );&lt;br /&gt;
                //vPlugins[ getName() &lt;br /&gt;
                vPlugins-&amp;gt;push_back( dlhandle );&lt;br /&gt;
        }&lt;br /&gt;
 #endif&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Dlopen_code_example&amp;diff=9879</id>
		<title>Dlopen code example</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Dlopen_code_example&amp;diff=9879"/>
		<updated>2007-02-13T03:18:48Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;void loadPlugins( const char *path ) {&lt;br /&gt;
#ifndef LL_WINDOWS&lt;br /&gt;
        int (*slp_plugin_init)(plugin_interface *);&lt;br /&gt;
        &lt;br /&gt;
        DIR * plugindir;&lt;br /&gt;
        struct dirent * mydirent;&lt;br /&gt;
        void * dlhandle;&lt;br /&gt;
        char plugin_name[FILENAME_MAX];&lt;br /&gt;
        &lt;br /&gt;
        plugindir = opendir( path );&lt;br /&gt;
    if( NULL == plugindir ) {&lt;br /&gt;
                llwarns &amp;lt;&amp;lt; &amp;quot;Could not open plugins directory: &amp;quot; &amp;lt;&amp;lt; path &amp;lt;&amp;lt; llendl;&lt;br /&gt;
                return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        while (mydirent = readdir(plugindir)) {&lt;br /&gt;
                if(!strcasestr(mydirent-&amp;gt;d_name, PLUGINEXT)) {&lt;br /&gt;
                        fprintf(stderr, &amp;quot;Ignoring non-plugin directory entry %s\n&amp;quot;, mydirent-&amp;gt;d_name);&lt;br /&gt;
                        continue;&lt;br /&gt;
                }&lt;br /&gt;
                &lt;br /&gt;
                snprintf(plugin_name, sizeof(plugin_name), &amp;quot;%s%s%s&amp;quot;, path, gDirUtilp-&amp;gt;getDirDelimiter().c_str(), mydirent-&amp;gt;d_name);&lt;br /&gt;
                fprintf(stderr, &amp;quot;Trying to load plugin: %s\n&amp;quot;, plugin_name);&lt;br /&gt;
                dlhandle = dlopen(plugin_name, RTLD_LAZY);&lt;br /&gt;
                if (dlhandle==NULL) {&lt;br /&gt;
                        fprintf(stderr,&amp;quot;Error opening %s:  %s\n&amp;quot;, plugin_name, dlerror());&lt;br /&gt;
                        continue;&lt;br /&gt;
                }&lt;br /&gt;
                &lt;br /&gt;
                slp_plugin_init = (int(*)(plugin_interface*))dlsym(dlhandle, &amp;quot;initOSLPlugin&amp;quot;);&lt;br /&gt;
                if (!slp_plugin_init) {&lt;br /&gt;
                        fprintf(stderr,&amp;quot;Error looking up initOSLPlugin:  %s\n&amp;quot;, dlerror());&lt;br /&gt;
                        dlclose(dlhandle);&lt;br /&gt;
                        continue;&lt;br /&gt;
                }&lt;br /&gt;
                slp_plugin_init(&amp;amp;gPluginInterface);&lt;br /&gt;
                //char * (*getName)(void) = (char *(*)())dlsym(*(itPlugins), &amp;quot;getPluginName&amp;quot; );&lt;br /&gt;
                //vPlugins[ getName() &lt;br /&gt;
                vPlugins-&amp;gt;push_back( dlhandle );&lt;br /&gt;
        }&lt;br /&gt;
 #endif&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Plugin_architecture_Low-level_Architecture&amp;diff=9875</id>
		<title>Plugin architecture Low-level Architecture</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Plugin_architecture_Low-level_Architecture&amp;diff=9875"/>
		<updated>2007-02-13T03:11:49Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The three technical challenges for creating a plugin architecture are as follows:&lt;br /&gt;
&lt;br /&gt;
== Code loading ==&lt;br /&gt;
Dynamic loading of natively-compiled executable code can be accomplished with dlopen / dlsym in Linux and MacOSX and LoadLibrary on Win32.&lt;br /&gt;
&lt;br /&gt;
[[dlopen code example]]&lt;br /&gt;
&lt;br /&gt;
== Calls from viewer to plugin (hooks) ==&lt;br /&gt;
&lt;br /&gt;
In order to override or enhance existing functionality in the viewer, we need to be able to replace some code with our own.  One way to do this would be to install &amp;quot;hooks&amp;quot; into commonly-used functions.  In the example implementation code below, you can hook any function by adding &#039;PLUGIN_HOOK(&amp;quot;function_name&amp;quot;, data1, data2)&#039; to the top of the function.&lt;br /&gt;
&lt;br /&gt;
When that macro is called, it looks to see if any hooks have been registered with a name that matches &amp;quot;function_name&amp;quot;.  If so, it executes each one in turn.&lt;br /&gt;
&lt;br /&gt;
Each hook function can affect program execution in one of three ways:&lt;br /&gt;
&lt;br /&gt;
* Pass event through -- a function might decide to ignore this hook based on the contents of data1 and data2, or it might do something which doesn&#039;t disrupt the program flow (such as adding data to an internal list for later use, or displaying a dialog box).  In this case, it should just return TRUE.&lt;br /&gt;
* Modify params, pass event through -- as above, except the hook function can modify the contents of data1 and/or data2 before returning TRUE&lt;br /&gt;
* Swallow event:  Sometimes, we want to completely override the function being hooked, for various reasons -- in this case, the plugin should return FALSE.&lt;br /&gt;
&lt;br /&gt;
PLUGIN_HOOK executes each function in turn; if it function returns FALSE, it just issues a &#039;return&#039; in the context of the hooked function.  If all hooks return TRUE, control will eventually be passed to the hooked function.&lt;br /&gt;
&lt;br /&gt;
[[hook example code]]&lt;br /&gt;
== Calls from plugin to viewer (exposing an API) ==&lt;br /&gt;
&lt;br /&gt;
Most plugins will want to call into the client and have it do things like display dialog boxes, send IMs, etc.  Unfortunately, there&#039;s no simple way to do this.&lt;br /&gt;
&lt;br /&gt;
Ideally, most interesting functions in the viewer would be broken out into dylibs / dlls so that plugins could link against them.  This probably isn&#039;t practical.&lt;br /&gt;
&lt;br /&gt;
The alternate solution is to pick a number of useful functions, build a function pointer table, and allow plugins to ask for them by name.&lt;br /&gt;
&lt;br /&gt;
[[function pointer example code]]&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Plugin_architecture_Low-level_Architecture&amp;diff=9872</id>
		<title>Plugin architecture Low-level Architecture</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Plugin_architecture_Low-level_Architecture&amp;diff=9872"/>
		<updated>2007-02-13T03:07:39Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The three technical challenges for creating a plugin architecture are as follows:&lt;br /&gt;
&lt;br /&gt;
== Code loading ==&lt;br /&gt;
Dynamic loading of natively-compiled executable code can be accomplished with dlopen / dlsym in Linux and MacOSX and LoadLibrary on Win32.&lt;br /&gt;
&lt;br /&gt;
[[dlopen code example]]&lt;br /&gt;
&lt;br /&gt;
== Calls from viewer to plugin (hooks) ==&lt;br /&gt;
&lt;br /&gt;
In order to override or enhance existing functionality in the viewer, we need to be able to replace some code with our own.  One way to do this would be to install &amp;quot;hooks&amp;quot; into commonly-used functions.  In the example implementation code below, you can hook any function by adding &#039;PLUGIN_HOOK(&amp;quot;function_name&amp;quot;, data1, data2)&#039; to the top of the function.&lt;br /&gt;
&lt;br /&gt;
When that macro is called, it looks to see if any hooks have been registered with a name that matches &amp;quot;function_name&amp;quot;.  If so, it executes each one in turn.&lt;br /&gt;
&lt;br /&gt;
Each hook function can affect program execution in one of three ways:&lt;br /&gt;
&lt;br /&gt;
* Pass event through -- a function might decide to ignore this hook based on the contents of data1 and data2, or it might do something which doesn&#039;t disrupt the program flow (such as adding data to an internal list for later use, or displaying a dialog box).  In this case, it should just return TRUE.&lt;br /&gt;
* Modify params, pass event through -- as above, except the hook function can modify the contents of data1 and/or data2 before returning TRUE&lt;br /&gt;
* Swallow event:  Sometimes, we want to completely override the function being hooked, for various reasons -- in this case, the plugin should return FALSE.&lt;br /&gt;
&lt;br /&gt;
PLUGIN_HOOK executes each function in turn; if it function returns FALSE, it just issues a &#039;return&#039; in the context of the hooked function.  If all hooks return TRUE, control will eventually be passed to the hooked function.&lt;br /&gt;
&lt;br /&gt;
== Calls from plugin to viewer (exposing an API) ==&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Plugin_architecture_Low-level_Architecture&amp;diff=9869</id>
		<title>Plugin architecture Low-level Architecture</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Plugin_architecture_Low-level_Architecture&amp;diff=9869"/>
		<updated>2007-02-13T02:57:30Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: /* Code loading */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The three technical challenges for creating a plugin architecture are as follows:&lt;br /&gt;
&lt;br /&gt;
== Code loading ==&lt;br /&gt;
Dynamic loading of natively-compiled executable code can be accomplished with dlopen / dlsym in Linux and MacOSX and LoadLibrary on Win32.&lt;br /&gt;
&lt;br /&gt;
[[dlopen code example]]&lt;br /&gt;
&lt;br /&gt;
== Calls from viewer to plugin (hooks) ==&lt;br /&gt;
== Calls from plugin to viewer (exposing an API) ==&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Plugin_architecture_Low-level_Architecture&amp;diff=9867</id>
		<title>Plugin architecture Low-level Architecture</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Plugin_architecture_Low-level_Architecture&amp;diff=9867"/>
		<updated>2007-02-13T02:55:21Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The three technical challenges for creating a plugin architecture are as follows:&lt;br /&gt;
&lt;br /&gt;
== Code loading ==&lt;br /&gt;
== Calls from viewer to plugin (hooks) ==&lt;br /&gt;
== Calls from plugin to viewer (exposing an API) ==&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Plugin_architecture&amp;diff=9866</id>
		<title>Plugin architecture</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Plugin_architecture&amp;diff=9866"/>
		<updated>2007-02-13T02:48:30Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: /* Table Of Contents */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As of this writing (February 12, 2007), there&#039;s not an official plugin architecture in the Second Life viewer.  However, there&#039;s been a lot of interest in developing one.  This page (and the pages it links to) are an attempt to capture a lot of the informal discussion that has occurred so far.&lt;br /&gt;
&lt;br /&gt;
== Table Of Contents ==&lt;br /&gt;
&lt;br /&gt;
# Discussions&lt;br /&gt;
## [[Plugin_architecture_survey|Survey of Client Plugins as Potential Models]]&lt;br /&gt;
## [[Plugin_architecture_Security|Security Model Issues]]&lt;br /&gt;
## [[Plugin_architecture_Low-level Architecture|Low-level architecture]]&lt;br /&gt;
## [[Plugin_architecture_Cross_Platform|Cross Platform Issues]]&lt;br /&gt;
## [[Plugin_architecture_Stability|PlugIns affecting Client Stability]]&lt;br /&gt;
## [[Plugin_LSL_Communication|Plugin &amp;lt;--&amp;gt; LSL Communication Channels]]&lt;br /&gt;
# Required Changes&lt;br /&gt;
&lt;br /&gt;
== Required Changes ==&lt;br /&gt;
Some changes in the code will be required to support plugins. &lt;br /&gt;
&lt;br /&gt;
* Complete GUI and other classes with functions that would be expected to exist, but don&#039;t because nothing needed them yet. For instance, add method overloads that should logically exist.&lt;br /&gt;
* Allow multiple callbacks per message, as well as unregistering a previously registered one. Currently only one callback can be registered per message type.&lt;br /&gt;
* Verify that all the callbacks work in such a way that they wouldn&#039;t be confused by plugins. When a callback for a reply to a request runs it must make sure that the data to arrived is what was requested, and if not, ignore it.&lt;br /&gt;
* Add internal callbacks for events such as rendering a frame, receiving a chat message, etc.&lt;br /&gt;
&lt;br /&gt;
[[Category:Feature Requests]]&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Plugin_architecture&amp;diff=9865</id>
		<title>Plugin architecture</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Plugin_architecture&amp;diff=9865"/>
		<updated>2007-02-13T02:46:51Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: /* Table Of Contents */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As of this writing (February 12, 2007), there&#039;s not an official plugin architecture in the Second Life viewer.  However, there&#039;s been a lot of interest in developing one.  This page (and the pages it links to) are an attempt to capture a lot of the informal discussion that has occurred so far.&lt;br /&gt;
&lt;br /&gt;
== Table Of Contents ==&lt;br /&gt;
&lt;br /&gt;
# Discussions&lt;br /&gt;
## [[Plugin_architecture_survey|Survey of Client Plugins as Potential Models]]&lt;br /&gt;
## [[Plugin_architecture_Security|Security Model Issues]]&lt;br /&gt;
## [[Plugin_architecture_Dynamic_Loading|Dynamic Loading Of Plugins]]&lt;br /&gt;
## [[Plugin_architecture_Hooks|Communications between plugins and viewer (hooks)]]&lt;br /&gt;
## [[Plugin_architecture_Cross_Platform|Cross Platform Issues]]&lt;br /&gt;
## [[Plugin_architecture_Stability|PlugIns affecting Client Stability]]&lt;br /&gt;
## [[Plugin_LSL_Communication|Plugin &amp;lt;--&amp;gt; LSL Communication Channels]]&lt;br /&gt;
# Required Changes&lt;br /&gt;
&lt;br /&gt;
== Required Changes ==&lt;br /&gt;
Some changes in the code will be required to support plugins. &lt;br /&gt;
&lt;br /&gt;
* Complete GUI and other classes with functions that would be expected to exist, but don&#039;t because nothing needed them yet. For instance, add method overloads that should logically exist.&lt;br /&gt;
* Allow multiple callbacks per message, as well as unregistering a previously registered one. Currently only one callback can be registered per message type.&lt;br /&gt;
* Verify that all the callbacks work in such a way that they wouldn&#039;t be confused by plugins. When a callback for a reply to a request runs it must make sure that the data to arrived is what was requested, and if not, ignore it.&lt;br /&gt;
* Add internal callbacks for events such as rendering a frame, receiving a chat message, etc.&lt;br /&gt;
&lt;br /&gt;
[[Category:Feature Requests]]&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Plugin_architecture_Dynamic_Loading&amp;diff=9864</id>
		<title>Plugin architecture Dynamic Loading</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Plugin_architecture_Dynamic_Loading&amp;diff=9864"/>
		<updated>2007-02-13T02:46:07Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This can be accomplished using dlopen / dlsym on MacOS and Linux platforms; I understand that LoadLibrary can be used for a similar function under Win32.&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Plugin_architecture&amp;diff=9863</id>
		<title>Plugin architecture</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Plugin_architecture&amp;diff=9863"/>
		<updated>2007-02-13T02:42:01Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: /* Table Of Contents */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As of this writing (February 12, 2007), there&#039;s not an official plugin architecture in the Second Life viewer.  However, there&#039;s been a lot of interest in developing one.  This page (and the pages it links to) are an attempt to capture a lot of the informal discussion that has occurred so far.&lt;br /&gt;
&lt;br /&gt;
== Table Of Contents ==&lt;br /&gt;
&lt;br /&gt;
# Discussions&lt;br /&gt;
## [[Plugin_architecture_survey|Survey of Client Plugins as Potential Models]]&lt;br /&gt;
## [[Plugin_architecture_Security|Security Model Issues]]&lt;br /&gt;
## [[Plugin_architecture_Dynamic_Loading|Dynamic Updating and Loading Of Plugins]]&lt;br /&gt;
## [[Plugin_architecture_Cross_Platform|Cross Platform Issues]]&lt;br /&gt;
## [[Plugin_architecture_Stability|PlugIns affecting Client Stability]]&lt;br /&gt;
## [[Plugin_LSL_Communication|Plugin &amp;lt;--&amp;gt; LSL Communication Channels]]&lt;br /&gt;
# Required Changes&lt;br /&gt;
&lt;br /&gt;
== Required Changes ==&lt;br /&gt;
Some changes in the code will be required to support plugins. &lt;br /&gt;
&lt;br /&gt;
* Complete GUI and other classes with functions that would be expected to exist, but don&#039;t because nothing needed them yet. For instance, add method overloads that should logically exist.&lt;br /&gt;
* Allow multiple callbacks per message, as well as unregistering a previously registered one. Currently only one callback can be registered per message type.&lt;br /&gt;
* Verify that all the callbacks work in such a way that they wouldn&#039;t be confused by plugins. When a callback for a reply to a request runs it must make sure that the data to arrived is what was requested, and if not, ignore it.&lt;br /&gt;
* Add internal callbacks for events such as rendering a frame, receiving a chat message, etc.&lt;br /&gt;
&lt;br /&gt;
[[Category:Feature Requests]]&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:Version_control_repository&amp;diff=8307</id>
		<title>Talk:Version control repository</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:Version_control_repository&amp;diff=8307"/>
		<updated>2007-02-05T10:14:41Z</updated>

		<summary type="html">&lt;p&gt;Bushing Spatula: bushing speaks!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== SVN ==&lt;br /&gt;
&lt;br /&gt;
I&#039;m happy with a read only SVN.&lt;br /&gt;
&lt;br /&gt;
We are all developers.  We can set up our own local SVN if we want a sandbox. [[User:Gigs Taggart|Gigs Taggart]] 15:13, 9 January 2007 (PST)&lt;br /&gt;
&lt;br /&gt;
Agreed.&lt;br /&gt;
I think our repo should have a struture like....&lt;br /&gt;
* /trunk/slviewer/      Root of what we are given.  You basically just need to check this one directory out to build the client.&lt;br /&gt;
* /tags/slviewer/slviewer-*/     tag of each revision that&#039;s distroed by LL as a set, perhaps with it&#039;s binaries, and the build outputs.  (map files and .asm files anyone?)&lt;br /&gt;
* /branches/slviewer/slviewer-*.1/    Branches to deal with bugs that happen once a tag has been made.  Any changes fixed on a branch should also be applied to the trunk too.&lt;br /&gt;
[[User:Kunnis Basiat|Kunnis Basiat]] 18:38, 9 January 2007 (PST)&lt;br /&gt;
&lt;br /&gt;
* [[User:Adam Zaius|Adam Zaius]] 06:38, 8 January 2007 (PST) votes for SVN&lt;br /&gt;
** Directory structure something like:&lt;br /&gt;
*** /trunk -- Only editable by Linden Lab&lt;br /&gt;
*** /branches/users/&amp;lt;username&amp;gt;/ -- unlimited permissions by owner/creator for third-party source&lt;br /&gt;
&lt;br /&gt;
Do we want to integrate the VCS with the Second Life authentication?  Pluggability of authentication scheme seems like an important axis to consider. --[[User:Which Linden|Which Linden]] 09:27, 8 January 2007 (PST)&lt;br /&gt;
&lt;br /&gt;
Giving users branches in SVN without a degree of trust is dangerous - purging history in SVN is intentionally very difficult, so a single (malicious) user could conceivably use up all the space in the server or host not-so-legal content (even if you svn rm something, it&#039;s still in the history). However if the trunk is pure svn, normal users can use things like svk if they want their own branches. --[[User:Ginko Bayliss|Ginko Bayliss]] 13:33, 9 January 2007 (PST)&lt;br /&gt;
&lt;br /&gt;
: Very good idea to consider (VCS w/ SLA). I would highly recommend sourceforge due to its known ability to handle major traffic; however, we would not have the SLA. Despite that, there are many professional and mature tools that work directly with SVN, for example Subclipse.&lt;br /&gt;
: I suggest a tier level repository with modes for production, test, and development, and each with their own trunk, branches, and tags. Production is not distributed and is mainly read-only except for the few who update it.  Production is updated with, and only from, approved patches from test. Test tier is updated by an approved group of individuals with patches from development tier. Test is not distributed but is not read-only like the production tier. Test is where people go to get latest working patches. It is similar to Debian&#039;s mid-tier.  Development can be distributed (people can host their own local sandbox), and it is write-enabled by a larger group responsible to merge code. Once code has been basically approved as working in development, it moves to test, so several patches to development may result in only one patch to test, and that would be the same from test to production. [[User:Dzonatas Sol|Dzonatas Sol]] 10:04, 10 January 2007 (PST)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[User:Eddy Stryker|Eddy Stryker]] 13:22, 9 January 2007 (PST) votes against SVN&lt;br /&gt;
* Branching/merging capabilities are hacked in, so instead of doing push or pull commands you are looking up revision numbers to figure out when you last backported and where the new merge should start&lt;br /&gt;
* No distributed version control like bitkeeper, git, mercurial, etc without using SVK which is a less than ideal solution&lt;br /&gt;
* Not designed for very large codebases like Second Life, where branching becomes unbearable&lt;br /&gt;
** To continue on this point, we had to repair the opensecondlife.org svn database over a dozen times while checking in the thousands of files that make up the full codebase. It&#039;s centralized atomic nature seems to start falling apart when you have very big commits or similar operations going on and multiple other people are trying to check out&lt;br /&gt;
* SVN is a centralized repository system, it&#039;s designed to allow a group of people work together on the same codebase. LL would either have to create two million svn accounts, or have someone take account requests and process them, including setting up permissions for each sandbox... it would become a nightmare very quickly. That&#039;s why large distributed projects like the Linux kernel used distributed version control. They use Git which is Linux only right now, but Mercurial is proving to be a very good competitor to Git with support for all major operating systems&lt;br /&gt;
&lt;br /&gt;
[[User:Kunnis Basiat|Kunnis Basiat]] 22:35, 14 January 2007 (PST)&lt;br /&gt;
* While I agree with the fact that branching and merging is a bit wierd in SVN, it was designed that way from the start, it was designed to get around several of the design flaws that were present in CVS, though I agree it&#039;s not as intunitive as it should be, it allows for really good tracking, but it&#039;s also a bit confusing.  LL has been using SVN for a while, so they should be familiar with how version control in SVN works.&lt;br /&gt;
* I Find SVN to be really stable.I&#039;ve never had a problem with SVN, and I&#039;ve used it for a couple years professionally, and I&#039;ve been helping my latest company migrate to SVN.  The only annoyance I have about SVN is it&#039;s lack of an &amp;quot;obliterate&amp;quot; command, which there is a workaround for, and the schedule of an addition of the command.  Other then that issue, SVN has been in use for several years, it&#039;s a well tested tool, and if any issues arise while using it, it&#039;s likley that you can find support for it.  I&#039;ve only had to break out svnadmin once (to deal with the lack of obliterate, and I found a step-by-step on how to do it.)&lt;br /&gt;
* SVN is used by KDE.  It has both binary and source files, which reflects what we would be checking into OpenSL, and I think that KDE would have more users editing it, and I&#039;m pretty sure it has a larger codebase.&lt;br /&gt;
* I don&#039;t know what problem you had with your repo. I am using the windows version of SVN, and I took my existing repo that I&#039;ve used for other projects and checked in all of the slviewer and libs in one big checkin, with no problems.  It copied all ~9000 files and 160megs in about 5 mins.&lt;br /&gt;
* I agree that LL creating account for every developer is very unreasonable.  I think LL should host a repo that only has &amp;quot;gold&amp;quot; code on it, ready for production, with tags for each build.  There should not be a sandbox for every developer.  I think that we should submit patches to LL that are diffs from the head version of the repo, then a LL employee can apply the patch, then check&amp;amp;verify it works and passes all tests, then finally commit the patch to the repo.  What would the process for a LL employee to recieve a change, validate it, and apply it to production be with Mercurial?  I don&#039;t know enough about it to say what it&#039;s like.&lt;br /&gt;
* I Agree the lack of a Distributed Version Control sucks, you&#039;ve got me curious, I want to play with SVK now.&lt;br /&gt;
&lt;br /&gt;
[[User:Bushing Spatula|Bushing Spatula]] 02:14, 5 February 2007 (PST) votes against SVN, with further comments below&lt;br /&gt;
* I use SVN professionally.  We have a SVN repo with hundreds of thousands of lines of code (it&#039;s something like 2.9GB including history), and roughtly a dozen developers.  It works pretty well with the following use model:&lt;br /&gt;
** Each dev has his own set of code -- we almost never step on each others&#039; toes because the code is well-partitioned into subprojects&lt;br /&gt;
** All patches are initially saved as a branch -- one per bug -- which is then peer-reviewed.  Once it passes review, the patch is merged into trunk.&lt;br /&gt;
While this may or may not be similar to how LL does things in-house with SVN, I think this is very different then allowing outside contributions from many people, many of whom will step on each others toes, and many of whom will submit patches that will not be accepted.  See discussion below about distributed systems.&lt;br /&gt;
== Distributed version control ==&lt;br /&gt;
&lt;br /&gt;
One reason I really like the distributed version control systems is because it really reduces the need for Linden Lab to be in the business of giving people their own sandboxes.  Many of the newer systems are very easy to host, and merging from multiple repositories is much easier. -- [[User:Rob Linden|Rob Linden]] 07:25, 8 January 2007 (PST)&lt;br /&gt;
&lt;br /&gt;
I agree.  Please, if you&#039;re interested in this debate, go read up on the pros and cons of distributed version control before proceeding -- it&#039;s a complicated, nuanced issue.&lt;br /&gt;
My crude summary:&lt;br /&gt;
* DVC systems allow everyone to set up their own private, spiffy repository.  There&#039;s no need for LL to make every developer an account, because&lt;br /&gt;
* It&#039;s really easy to make changes on your local repo, and really easy to integrate changes from upstream (IE new LL source drops), so you make sure your changes are still relevant and still valid with every release&lt;br /&gt;
* Once you&#039;re happy with your code, it&#039;s easy to make patches that you can pass around, post on mailing lists, etc -- and other people can seamlessly drop them into their own local repository without breaking other stuff&lt;br /&gt;
* Once everyone loves a patch, it&#039;s very easy to send that patch to LL in a form that is very easy for them to apply to their tree.&lt;br /&gt;
&lt;br /&gt;
I&#039;d tend to go with Mercurial, because it seems to have the greatest support and mindshare of the DVC systems right now, but I&#039;d be happy with any of them. [[User:Bushing Spatula|Bushing Spatula]] 02:14, 5 February 2007 (PST)&lt;br /&gt;
=== Mercurial ===&lt;br /&gt;
Mercurial&#039;s claim: Mercurial is a fast, lightweight Source Control Management system designed for efficient handling of very large distributed projects.&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[User:Baba Yamamoto|Baba Yamamoto]] votes for this. &lt;br /&gt;
*No central repository. &lt;br /&gt;
*Easier branching and merging.&lt;br /&gt;
&lt;br /&gt;
=== Darcs ===&lt;br /&gt;
&lt;br /&gt;
Darcs is something you may want to investigate. I&#039;ve used it for other projects, and it was simple and effective enough that the less technical folks have actually started using it for their own projects, it is so simple and effective. A possible con would be that it IS written in Haskell.. but that&#039;s not that problematic. --[[User:Ky Aska|Ky Aska]] 15:59, 8 January 2007 (PST)&lt;br /&gt;
&lt;br /&gt;
We tried using darcs for a while in-house, and really &amp;lt;em&amp;gt;wanted&amp;lt;/em&amp;gt; it to work, but it would frequently never finish operations on windows because it would consume too much memory. [[User:Phoenix Linden|Phoenix Linden]] 09:25, 9 January 2007 (PST)&lt;br /&gt;
&lt;br /&gt;
Out of curiosity, how long ago was darcs tried? It might&#039;ve gotten better since then - though I&#039;ve heard that performance during conflict resolution is still rather bad. --[[User:Ginko Bayliss|Ginko Bayliss]] 16:32, 9 January 2007 (PST)&lt;br /&gt;
&lt;br /&gt;
[[User:Don Linden|Don]] and [[User:Kelly Linden|Kelly]] Linden experimented with darcs between 2006.02 and 2006.03.  The version was 1.0.2 on linux.  The Win and Mac versions may have been different.  The conclusion was that darcs could not yet handle large repositories. -- [[User:Andrew Linden|Andrew Linden]] 2006.01.10 09:21 (PST)&lt;br /&gt;
&lt;br /&gt;
=== Bazaar ===&lt;br /&gt;
Bazaar seems to be the hot VCS of choice now days, might be worth considering. Not sure if the development model is applicable to SL or not. It&#039;s got quite a lot of buzz recently in the Linux/Ubuntu/Launchpad world, also seems to have Windows support. http://bazaar-vcs.org/ &lt;br /&gt;
&lt;br /&gt;
Might also be worth looking at using launchpad itself which includes the Bazaar VCS, bug tracking and other stuff, The back end is closed currently but Canonical might be quite happy to allow Linden labs to have a copy of it to host, Mark Shuttleworth recently post about SL http://www.markshuttleworth.com/archives/72 although it would probably be quite a lot of work to setup and the features like bug tracking might be duplicated with existing systems used by Linden (although it seems like it would be fairly easy to integrate them. --[[User:Hegemon Skall|Hegemon Skall]] 13:32, 26 January 2007 (PST)&lt;br /&gt;
&lt;br /&gt;
=== Comparisons ===&lt;br /&gt;
Thought these might be useful, basically a list of features supported by each VCS:&lt;br /&gt;
&lt;br /&gt;
http://bazaar-vcs.org/RcsComparisons&lt;br /&gt;
http://en.wikipedia.org/wiki/Comparison_of_revision_control_software&lt;br /&gt;
--[[User:Hegemon Skall|Hegemon Skall]] 17:38, 27 January 2007 (PST)&lt;/div&gt;</summary>
		<author><name>Bushing Spatula</name></author>
	</entry>
</feed>