diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp
index b4e4cac92e3ab6edf32ad40d15cf92a281c0a780..56b4e559a24ca6c42ab7805760980f06531340c8 100644
--- a/indra/llui/llkeywords.cpp
+++ b/indra/llui/llkeywords.cpp
@@ -33,6 +33,7 @@
 #include "llsdserialize.h"
 #include "lltexteditor.h"
 #include "llstl.h"
+#include "llsdutil.h"
 
 inline bool LLKeywordToken::isHead(const llwchar* s) const
 {
@@ -109,6 +110,7 @@ void LLKeywords::addToken(LLKeywordToken::ETokenType type,
 	case LLKeywordToken::TT_LABEL:
 	case LLKeywordToken::TT_SECTION:
 	case LLKeywordToken::TT_TYPE:
+	case LLKeywordToken::TT_PREPROC:
 	case LLKeywordToken::TT_WORD:
 		mWordTokenMap[key] = new LLKeywordToken(type, color, key, tool_tip, LLWStringUtil::null);
 		break;
@@ -193,7 +195,7 @@ LLColor4 LLKeywords::getColorGroup(std::string_view key_in)
 		script_colors.push_back(LLUIColorTable::instance().getColor("SyntaxLslConstant"));
 	}
 
-	if (key_in == "functions")
+	if (key_in == "functions" || key_in == "preprocessor")
 	{
 		return script_colors[SyntaxLslFunction].get();
 	}
@@ -242,6 +244,34 @@ LLColor4 LLKeywords::getColorGroup(std::string_view key_in)
 void LLKeywords::initialize(LLSD SyntaxXML)
 {
 	mSyntax = SyntaxXML;
+	
+	std::string preproc_tokens = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keywords_lsl_preproc.xml");
+	if (gDirUtilp->fileExists(preproc_tokens))
+	{
+		LLSD content;
+		llifstream file;
+		file.open(preproc_tokens.c_str());
+		if (file.is_open())
+		{
+			if(LLSDSerialize::fromXML(content, file) == LLSDParser::PARSE_FAILURE)
+			{
+				LL_INFOS() << "Failed to parse preproc token file" << LL_ENDL;
+			}
+			file.close();
+		}
+		else
+		{
+			LL_WARNS("SyntaxLSL") << "Failed to open: " << preproc_tokens << LL_ENDL;
+		}
+
+		if (content.isMap())
+		{
+			if (content.has("preprocessor"))
+			{
+				mSyntax["preprocessor"] = llsd_clone(content["preprocessor"]);
+			}
+		}
+	}
 	mLoaded = true;
 }
 
@@ -314,6 +344,10 @@ void LLKeywords::processTokensGroup(const LLSD& tokens, std::string_view group)
 	{
 		token_type = LLKeywordToken::TT_TYPE;
 	}
+	else if (group == "preprocessor")
+	{
+		token_type = LLKeywordToken::TT_PREPROC;
+	}
 
 	color_group = getColorGroup(group);
 	LL_DEBUGS("SyntaxLSL") << "Group: '" << group << "', using color: '" << color_group << "'" << LL_ENDL;
@@ -680,10 +714,10 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
 
 			// check against words
 			llwchar prev = cur > base ? *(cur-1) : 0;
-			if( !iswalnum( prev ) && (prev != '_') )
+			if( !iswalnum( prev ) && (prev != '_') && (prev != '#'))
 			{
 				const llwchar* p = cur;
-				while( iswalnum( *p ) || (*p == '_') )
+				while( *p && ( iswalnum( *p ) || (*p == '_') || (*p == '#') ) )
 				{
 					p++;
 				}
diff --git a/indra/llui/llkeywords.h b/indra/llui/llkeywords.h
index 9fce3af3e31b6f5600c048c28c05a4da86e96b95..9e3cc9370c2b109615a5ff92782a7286e2240e0a 100644
--- a/indra/llui/llkeywords.h
+++ b/indra/llui/llkeywords.h
@@ -68,7 +68,8 @@ class LLKeywordToken
 		TT_FUNCTION,						// WORD
 		TT_LABEL,							// LINE
 		TT_SECTION,							// WORD
-		TT_TYPE								// WORD
+		TT_TYPE,							// WORD
+		TT_PREPROC							// WORD
 	} ETokenType;
 
 	LLKeywordToken( ETokenType type, const LLColor4& color, const LLWString& token, const LLWString& tool_tip, const LLWString& delimiter  )
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 0a58daf107a47abce6834566d7f3f5301c701cc2..b276ee740515ab172a8796d49c87617f28d205b4 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -320,8 +320,8 @@ bool LLTextBase::truncate()
 {
 	BOOL did_truncate = FALSE;
 
-	// First rough check - if we're less than 1/4th the size, we're OK
-	if (getLength() >= S32(mMaxTextByteLength / 4))
+	// First rough check - if we're less than 1/2th the size, we're OK
+	if (getLength() >= S32(mMaxTextByteLength / 2))
 	{	
 		// Have to check actual byte size
 		S32 utf8_byte_size = 0;
@@ -953,7 +953,8 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
 
 	getViewModel()->getEditableDisplay().insert(pos, wstr);
 
-	if ( truncate() )
+	//HACK: If we are readonly we shouldn't need to truncate
+	if ( !mReadOnly && truncate() )
 	{
 		insert_len = getLength() - old_len;
 	}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 4292777085dedf3782084205c1779138b872cac3..02982bb836e386cd26c747ad3c971b283c901274 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -143,6 +143,8 @@ set(viewer_SOURCE_FILES
     altoolalign.cpp
     alunzip.cpp
     alviewermenu.cpp
+    fslslpreproc.cpp
+    fslslpreprocviewer.cpp
     groupchatlistener.cpp
     llagentwearablesfetch.cpp
     llaccountingcostmanager.cpp
@@ -853,6 +855,8 @@ set(viewer_HEADER_FILES
     altoolalign.h
     alunzip.h
     alviewermenu.h
+    fslslpreproc.h
+    fslslpreprocviewer.h
     groupchatlistener.h
     llaccountingcost.h
     llagentwearablesfetch.h
diff --git a/indra/newview/app_settings/keywords_lsl_preproc.xml b/indra/newview/app_settings/keywords_lsl_preproc.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e1786022fd4fa1f38db0342c7fe12d9e2b673550
--- /dev/null
+++ b/indra/newview/app_settings/keywords_lsl_preproc.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<llsd>
+   <map>
+      <key>preprocessor</key>
+      <map>
+         <key>#assert</key>
+         <map>
+            <key>tooltip</key>
+            <string>Allows definition of preprocessor variables that do not conflict with names in the program name space</string>
+         </map>
+         <key>#define</key>
+         <map>
+            <key>tooltip</key>
+            <string>When the preprocessor encounters this directive, it replaces any occurrence of identifier in the rest of the code by replacement</string>
+         </map>
+         <key>#elif</key>
+         <map>
+            <key>tooltip</key>
+            <string>Specify some condition to be met in order for the portion of code they surround to be compiled</string>
+         </map>
+         <key>#else</key>
+         <map>
+            <key>tooltip</key>
+            <string>Specify some condition to be met in order for the portion of code they surround to be compiled</string>
+         </map>
+         <key>#endif</key>
+         <map>
+            <key>tooltip</key>
+            <string>Closes an #if directive</string>
+         </map>
+         <key>#error</key>
+         <map>
+            <key>tooltip</key>
+            <string>Aborts the compilation process when it is found, generating a compilation the error that can be specified as its parameter</string>
+         </map>
+         <key>#ident</key>
+         <map>
+            <key>tooltip</key>
+            <string>Inserts a comment into the generated script</string>
+         </map>
+         <key>#sccs</key>
+         <map>
+            <key>tooltip</key>
+            <string>Inserts a comment into the generated script</string>
+         </map>
+         <key>#if</key>
+         <map>
+            <key>tooltip</key>
+            <string>Specifies some condition to be met in order for the portion of code they surround to be compiled</string>
+         </map>
+         <key>#ifdef</key>
+         <map>
+            <key>tooltip</key>
+            <string>Allows a section of a program to be compiled only if the macro that is specified as the parameter has been defined, no matter which its value is</string>
+         </map>
+         <key>#ifndef</key>
+         <map>
+            <key>tooltip</key>
+            <string>The code between #ifndef and #endif directives is only compiled if the specified identifier has not been previously defined</string>
+         </map>
+         <key>#import</key>
+         <map>
+            <key>tooltip</key>
+            <string>Instructs the preprocessor to look for type library files first in the directory of the file that contains the #import statement, and then in the directories of whatever files that include (#include) that file</string>
+         </map>
+         <key>#include</key>
+         <map>
+            <key>tooltip</key>
+            <string>When the preprocessor finds an #include directive it replaces it by the entire content of the specified file</string>
+         </map>
+         <key>#include_next</key>
+         <map>
+            <key>tooltip</key>
+            <string>Instructs the preprocessor to continue searching for the specified file name, and to include the subsequent instance encountered after the current directory</string>
+         </map>
+         <key>#line</key>
+         <map>
+            <key>tooltip</key>
+            <string>Controls the line number and file name</string>
+         </map>
+         <key>#pragma</key>
+         <map>
+            <key>tooltip</key>
+            <string>This directive is used to specify diverse options to the compiler. These options are specific for the platform and the compiler you use</string>
+         </map>
+         <key>#unassert</key>
+         <map>
+            <key>tooltip</key>
+            <string>Closes an #assert directive</string>
+         </map>
+         <key>#undef</key>
+         <map>
+            <key>tooltip</key>
+            <string>Undefines #define macro</string>
+         </map>
+         <key>#warning</key>
+         <map>
+            <key>tooltip</key>
+            <string>Generate a level one warning from a specific location in your code</string>
+         </map>
+         <key>#switch</key>
+         <map>
+            <key>tooltip</key>
+            <string>Allows selection among multiple sections of code, depending on the value of an integral expression</string>
+         </map>
+         <key>#case</key>
+         <map>
+            <key>tooltip</key>
+            <string>Used with #switch in a union</string>
+         </map>
+         <key>#break</key>
+         <map>
+            <key>tooltip</key>
+            <string>Stops processing further lines in a #switch directive</string>
+         </map>
+      </map>
+      <key>llsd-lsl-syntax-version</key>
+      <integer>2</integer><!-- increment only when the file format changes, not just the content -->
+    </map>
+</llsd>
\ No newline at end of file
diff --git a/indra/newview/app_settings/settings_alchemy.xml b/indra/newview/app_settings/settings_alchemy.xml
index 21e728cac6cfe14bf0da0649d57ca5cac6b40994..b613de9bc89f5756e04cb7a7c3a70403ad165885 100644
--- a/indra/newview/app_settings/settings_alchemy.xml
+++ b/indra/newview/app_settings/settings_alchemy.xml
@@ -343,6 +343,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>AlchemyInventoryScriptsMono</key>
+    <map>
+      <key>Comment</key>
+      <string>Control whether new scripts in inventory are mono(true) or lsl(false)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
     <key>AlchemyMoonWalk</key>
       <map>
       <key>Comment</key>
@@ -607,8 +618,85 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>AlchemyPointAtPrivate</key>
+    <key>AlchemyLSLPreprocessor</key>
+    <map>
+      <key>Comment</key>
+      <string>LSL Preprocessor</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>AlchemyPreProcLSLOptimizer</key>
+    <map>
+      <key>Comment</key>
+      <string>LSL Optimizer</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
+    <key>AlchemyPreProcLSLTextCompress</key>
+    <map>
+      <key>Comment</key>
+      <string>LSL Text Compress</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>AlchemyPreProcLSLLazyLists</key>
     <map>
+      <key>Comment</key>
+      <string>LSL Lazy Lists</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
+    <key>AlchemyPreProcLSLSwitch</key>
+    <map>
+      <key>Comment</key>
+      <string>LSL Switch Statements</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
+    <key>AlchemyPreProcEnableHDDInclude</key>
+    <map>
+      <key>Comment</key>
+      <string>Enable #include from local disk</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>AlchemyPreProcHDDIncludeLocation</key>
+    <map>
+      <key>Comment</key>
+      <string>Path for local disk includes</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string/>
+    </map>
+    <key>AlchemyPointAtPrivate</key>
+      <map>
       <key>Comment</key>
       <string>Disable setting current point at target</string>
       <key>Persist</key>
@@ -761,8 +849,8 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
-	<key>OpenSimSearchURL</key>
-	<map>
+    <key>OpenSimSearchURL</key>
+    <map>
       <key>Comment</key>
       <string>OpenSim fallback search url</string>
       <key>Persist</key>
@@ -771,7 +859,7 @@
       <string>String</string>
       <key>Value</key>
       <string>http://search.metaverseink.com/opensim/results.jsp?query=[QUERY]&amp;submit=[CATEGORY]</string>
-	</map>
+    </map>
     <key>RenderAutoMaskAlphaUseRMSE</key>
     <map>
       <key>Comment</key>
@@ -816,28 +904,28 @@
       <key>Value</key>
       <string></string>
     </map>
-	<key>RenderFocusPointLocked</key>
-	<map>
-		<key>Comment</key>
-		<string>Whether the focus point used for DoF is currently Locked in place</string>
-		<key>Persist</key>
-		<integer>0</integer>
-		<key>Type</key>
-		<string>Boolean</string>
-		<key>Value</key>
-		<integer>0</integer>
-	</map>
-	<key>RenderFocusPointFollowsPointer</key>
-	<map>
-		<key>Comment</key>
-		<string>Allows the Depth of Field focus to actively follow the mouse point</string>
-		<key>Persist</key>
-		<integer>0</integer>
-		<key>Type</key>
-		<string>Boolean</string>
-		<key>Value</key>
-		<integer>0</integer>
-	</map>
+    <key>RenderFocusPointLocked</key>
+    <map>
+        <key>Comment</key>
+        <string>Whether the focus point used for DoF is currently Locked in place</string>
+        <key>Persist</key>
+        <integer>0</integer>
+        <key>Type</key>
+        <string>Boolean</string>
+        <key>Value</key>
+        <integer>0</integer>
+    </map>
+    <key>RenderFocusPointFollowsPointer</key>
+    <map>
+        <key>Comment</key>
+        <string>Allows the Depth of Field focus to actively follow the mouse point</string>
+        <key>Persist</key>
+        <integer>0</integer>
+        <key>Type</key>
+        <string>Boolean</string>
+        <key>Value</key>
+        <integer>0</integer>
+    </map>
     <key>RenderSharpenMethod</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/fslslpreproc.cpp b/indra/newview/fslslpreproc.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3e7dadd8768ad0c9f81e7f374b78ed45879238c2
--- /dev/null
+++ b/indra/newview/fslslpreproc.cpp
@@ -0,0 +1,1586 @@
+/**
+ * @file fslslpreproc.cpp
+ * Copyright (c) 2010
+ *
+ * Modular Systems All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *   3. Neither the name Modular Systems nor the names of its contributors
+ *      may be used to endorse or promote products derived from this
+ *      software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MODULAR SYSTEMS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MODULAR SYSTEMS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "fslslpreproc.h"
+
+#include "fslslpreprocviewer.h"
+#include "llagent.h"
+#include "llappviewer.h"
+#include "llinventoryfunctions.h"
+#include "lltrans.h"
+#include "llfilesystem.h"
+#include "llviewercontrol.h"
+#include "llcompilequeue.h"
+#include "llnotificationsutil.h"
+#include "llvoavatarself.h"
+
+class ScriptMatches : public LLInventoryCollectFunctor
+{
+public:
+	ScriptMatches(const std::string& name)
+	{
+		mName = name;
+	}
+
+	virtual ~ScriptMatches() {}
+
+	virtual bool operator()(LLInventoryCategory* cat,
+							LLInventoryItem* item)
+	{
+		return (item && item->getName() == mName && item->getType() == LLAssetType::AT_LSL_TEXT);
+	}
+
+private:
+	std::string mName;
+};
+
+LLUUID FSLSLPreprocessor::findInventoryByName(std::string name)
+{
+	LLInventoryModel::cat_array_t cats;
+	LLInventoryModel::item_array_t items;
+	ScriptMatches namematches(name);
+	gInventory.collectDescendentsIf(gInventory.getRootFolderID(), cats, items, FALSE, namematches);
+
+	if (!items.empty())
+	{
+		return items.front()->getUUID();
+	}
+	return LLUUID::null;
+}
+
+std::map<std::string,LLUUID> FSLSLPreprocessor::cached_assetids;
+
+#include <boost/assert.hpp>
+#include <boost/wave.hpp>
+#include <boost/wave/cpplexer/cpp_lex_token.hpp>    // token class
+#include <boost/wave/cpplexer/cpp_lex_iterator.hpp> // lexer class
+#include <boost/wave/preprocessing_hooks.hpp>
+#include <boost/regex.hpp>
+#include <boost/filesystem.hpp>
+
+using namespace boost::regex_constants;
+
+#define encode_start "//start_unprocessed_text\n/*"
+#define encode_end std::string("*/\n//end_unprocessed_text")
+
+// Definitions to split the expressions into parts to improve readablility
+// (using 'r' as namespace prefix for RE, to avoid conflicts)
+// The code relies on none of these expressions having capturing groups.
+#define rCMNT "//[^\\n]*+\\n|/\\*(?:(?!\\*/).)*+\\*/" // skip over single- or multi-line comments as a block
+#define rSPC "[^][{}()<>@A-Za-z0-9_.,:;!~&|^\"=%/*+-]"
+#define rREQ_SPC "(?:" rCMNT "|" rSPC ")++"
+#define rOPT_SPC "(?:" rCMNT "|" rSPC ")*+"
+#define rTYPE_ID "[a-z]++"
+#define rIDENT "[A-Za-z_][A-Za-z0-9_]*+"
+#define rCMNT_OR_STR rCMNT "|\"(?:[^\"\\\\]|\\\\[^\\n])*+\"" // skip over strings as a block too
+#define rDOT_MATCHES_NEWLINE "(?s)"
+
+std::string FSLSLPreprocessor::encode(const std::string& script)
+{
+	std::string otext = FSLSLPreprocessor::decode(script);
+	
+	bool mono = mono_directive(script);
+	
+	static const boost::regex preproc_encode_regex("([/*])(?=[/*|])", boost::regex::perl);
+	otext = boost::regex_replace(otext, preproc_encode_regex, "$1|");
+	
+	time_t utc_time = time_corrected();
+	std::string timeStr ="["+LLTrans::getString ("TimeMonth")+"]/["
+				 +LLTrans::getString ("TimeDay")+"]/["
+				 +LLTrans::getString ("TimeYear")+"] ["
+				 +LLTrans::getString ("TimeHour")+"]:["
+				 +LLTrans::getString ("TimeMin")+"]:["
+				 +LLTrans::getString("TimeSec")+"]";
+	LLSD substitution;
+	substitution["datetime"] = (S32) utc_time;
+	LLStringUtil::format (timeStr, substitution);
+
+	return fmt::format(FMT_COMPILE("//start_unprocessed_text\n/*{}*/\n//end_unprocessed_text\n//nfo_preprocessor_version 0\n//program_version {}\n//last_compiled {}\n{}"), otext, LLAppViewer::instance()->getWindowTitle(), timeStr, mono ? "//mono\n" : "//lsl2\n");
+}
+
+std::string FSLSLPreprocessor::decode(const std::string& script)
+{
+	static size_t startpoint = std::string_view(encode_start).length();
+	
+	std::string tip = script.substr(0, startpoint);
+	if (tip != encode_start)
+	{
+		LL_DEBUGS("FSLSLPreprocessor") << "No start" << LL_ENDL;
+		//if(sp != -1)trigger warningg/error?
+		return script;
+	}
+	
+	size_t end = script.find(encode_end);
+	if (end == std::string::npos)
+	{
+		LL_DEBUGS("FSLSLPreprocessor") << "No end" << LL_ENDL;
+		return script;
+	}
+
+	std::string data = script.substr(startpoint, end - startpoint);
+	LL_DEBUGS("FSLSLPreprocessor") << "data = " << data << LL_ENDL;
+
+	static const boost::regex escape_regex("([/*])\\|", boost::regex::perl);
+	data = boost::regex_replace(data, escape_regex, "$1");
+
+	//data = curl_unescape(data.c_str(),data.length());
+
+	return data;
+}
+
+
+static std::string scopeript2(const std::string_view top, S32 fstart, char left = '{', char right = '}')
+{
+	if (fstart >= S32(top.length()))
+	{
+		return "begin out of bounds";
+	}
+	
+	S32 cursor = fstart;
+	bool noscoped = true;
+	bool in_literal = false;
+	S32 count = 0;
+	char ltoken = ' ';
+	
+	do
+	{
+		char token = top[cursor];
+		if (token == '"' && ltoken != '\\')
+		{
+			in_literal = !in_literal;
+		}
+		else if (token == '\\' && ltoken == '\\')
+		{
+			token = ' ';
+		}
+		else if (!in_literal)
+		{
+			if (token == left)
+			{
+				count += 1;
+				noscoped = false;
+			}
+			else if (token == right)
+			{
+				count -= 1;
+				noscoped = false;
+			}
+		}
+		ltoken = token;
+		cursor++;
+	}
+	while ((count > 0 || noscoped) && cursor < S32(top.length()));
+
+	S32 end = (cursor - fstart);
+	if (end > S32(top.length()))
+	{
+		return "end out of bounds";
+	}
+	
+	return std::string(top.substr(fstart,(cursor-fstart)));
+}
+
+static void shredder(std::string& text)
+{
+	S32 cursor = 0;
+	if (text.empty())
+	{
+		text = "No text to shredder.";
+		return;
+	}
+
+	char ltoken = ' ';
+	do
+	{
+		char token = text[cursor];
+		if (token == '"' && ltoken != '\\')
+		{
+			ltoken = token;
+			token = text[++cursor];
+			while (cursor < S32(text.length()))
+			{
+				if (token == '\\' && ltoken == '\\')
+				{
+					token = ' ';
+				}
+				if (token == '"' && ltoken != '\\')
+				{
+					break;
+				}
+				ltoken = token;
+				++cursor;
+				token = text[cursor];
+			}
+		}
+		else if (token == '\\' && ltoken == '\\')
+		{
+			token = ' ';
+		}
+
+		if (token != 0xA && token != 0x9 && (
+		   token < 0x20 ||
+		   token == '#' || 
+		   token == '$' || 
+		   token == '\\' || 
+		   token == '\'' || 
+		   token == '?' ||
+		   token >= 0x7F))
+		{
+			text[cursor] = ' ';
+		}
+		ltoken = token;
+		++cursor;
+	}
+	while (cursor < S32(text.length()));
+}
+
+std::string FSLSLPreprocessor::lslopt(std::string script)
+{
+	
+	try
+	{
+		std::string bottom;
+		std::set<std::string> kept_functions;
+		std::map<std::string, std::string> functions;
+		std::vector<std::pair<std::string, std::string> > gvars;
+
+		{	// open new scope for local vars
+
+			// Loop over every declaration in the script, classifying it according to type.
+
+			static const boost::regex finddecls(
+				rDOT_MATCHES_NEWLINE
+				"(^" // Group 1: RE for a variable declaration.
+					rOPT_SPC // skip (but capture) leading whitespace and comments
+					// type<space or comments>identifier[<space or comments>]
+					rTYPE_ID rREQ_SPC "(" rIDENT ")" rOPT_SPC // Group 2: Identifier
+					"(?:=" // optionally with an assignment
+						// comments or strings or characters that are not a semicolon
+						"(?:" rCMNT_OR_STR "|[^;])++"
+					")?;" // the whole assignment is optional, the semicolon isn't
+				")"
+				"|"
+				"(^" // Group 3: RE for a function declaration (captures up to the identifier inclusive)
+					rOPT_SPC // skip (but capture) whitespace
+					// optionally: type<space or comments>, then ident
+					"(?:" rTYPE_ID rREQ_SPC ")?(" rIDENT ")" // Group 4: identifier
+				")"
+				rOPT_SPC
+				"\\(" // this opening paren is the key for it to be a function
+				"|"
+				"(^" // Group 5: State default, possibly preceded by syntax errors
+					rOPT_SPC // skip (but capture) whitespace
+					"(?:"
+						rCMNT_OR_STR // skip strings and comments
+						"|(?!"
+							rCMNT_OR_STR
+							"|(?<![A-Za-z0-9_])default(?![A-Za-z0-9_])"
+						")." // any character that does not start a comment/string/'default'
+					")*+" // don't backtrack
+					"(?<![A-Za-z0-9_])default(?![A-Za-z0-9_])"
+				")"
+			);
+
+			boost::smatch result;
+
+			std::string top = std::string("\n") + script;
+
+			while (boost::regex_search(top.cbegin(), top.cend(), result, finddecls))
+			{
+				S32 len;
+
+				if (result[1].matched)
+				{
+					// variable declaration
+					gvars.push_back(std::make_pair(result[2], result[0]));
+					len = std::distance(top.cbegin(), result[0].second);
+				}
+				else if (result[3].matched)
+				{
+					// function declaration
+					std::string funcname = result[4];
+					std::string funcb = scopeript2(top, 0);
+					functions[funcname] = funcb;
+					len = funcb.length();
+				}
+				else //if (result[5].matched) // assumed
+				{
+					// found end of globals or syntax error
+					bottom = top;
+					break;
+				}
+
+				// Delete the declaration just found
+				top.erase(0, len);
+			}
+
+			if (bottom.empty())
+			{
+				return script; // don't optimize if there's no default state
+			}
+		}
+
+		// Find function calls and add the used function declarations back.
+		// Each time a function is added to the script a new pass is done
+		// so that function calls inside the added functions are seen.
+
+		bool repass;
+		do
+		{
+			repass = false;
+			std::map<std::string, std::string>::iterator func_it;
+			for (func_it = functions.begin(); func_it != functions.end(); func_it++)
+			{
+
+				std::string funcname = func_it->first;
+
+				if (kept_functions.find(funcname) == kept_functions.end())
+				{
+					boost::smatch calls; 
+					//funcname has to be [a-zA-Z0-9_]+, so we know it's safe
+					boost::regex findcalls(rDOT_MATCHES_NEWLINE
+						"(?<![A-Za-z0-9_])(" + funcname + ")" rOPT_SPC "\\(" // a call to the function...
+						"|(?:"
+							rCMNT_OR_STR // or comment or string...
+							"|(?!"
+								rCMNT_OR_STR
+								"|(?<![A-Za-z0-9_])" + funcname + rOPT_SPC "\\("
+							")." // or any other character that is not the start for a match of the above
+						")"
+					);
+
+					std::string::const_iterator bstart = bottom.cbegin();
+					while (boost::regex_search(bstart, bottom.cend(), calls, findcalls, boost::match_default))
+					{
+						if (calls[1].matched)
+						{
+							std::string function = func_it->second;
+							kept_functions.insert(funcname);
+							bottom = function + bottom;
+							repass = true;
+							break;
+						}
+						else
+						{
+							bstart = calls[0].second;
+						}
+					}
+				}
+			}
+		}
+		while (repass);
+
+		// Find variable invocations and add the declarations back if used.
+		std::vector<std::pair<std::string, std::string> >::reverse_iterator var_it;
+		for (var_it = gvars.rbegin(); var_it != gvars.rend(); var_it++)
+		{
+			const std::string& varname = var_it->first;
+			boost::regex findvcalls(std::string() + rDOT_MATCHES_NEWLINE
+				"(?<![a-zA-Z0-9_.])(" + varname + ")(?![a-zA-Z0-9_\"])" // invocation of the variable
+				"|(?:" rCMNT_OR_STR // a comment or string...
+					"|(?!"
+						rCMNT_OR_STR
+						"|(?<![a-zA-Z0-9_.])" + varname + "(?![a-zA-Z0-9_\"])"
+					")." // or any other character that is not the start for a match of the above
+				")"
+			);
+			boost::smatch vcalls;
+			std::string::const_iterator bstart = bottom.cbegin();
+			while (boost::regex_search(bstart, bottom.cend(), vcalls, findvcalls, boost::match_default))
+			{
+				if (vcalls[1].matched)
+				{
+					bottom = var_it->second + bottom;
+					break;
+				}
+				else
+				{
+					bstart = vcalls[0].second;
+				}
+			}
+		}
+
+		script = bottom;
+	}
+	catch (const boost::regex_error& e)
+	{
+		LLStringUtil::format_map_t args;
+		args["[WHAT]"] = e.what();
+		std::string err = LLTrans::getString("fs_preprocessor_optimizer_regex_err", args);
+		LL_WARNS("FSLSLPreprocessor") << err << LL_ENDL;
+		display_error(err);
+		throw;
+	}
+	catch (const std::exception& e)
+	{
+		LLStringUtil::format_map_t args;
+		args["[WHAT]"] = e.what();
+		std::string err = LLTrans::getString("fs_preprocessor_optimizer_exception", args);
+		LL_WARNS("FSLSLPreprocessor") << err << LL_ENDL;
+		display_error(err);
+		throw;
+	}
+	return script;
+}
+
+std::string FSLSLPreprocessor::lslcomp(std::string script)
+{
+	try
+	{
+		shredder(script);
+		static const boost::regex comp_regex("(\\s+)", boost::regex::perl);
+		script = boost::regex_replace(script, comp_regex, "\n");
+	}
+	catch (boost::regex_error& e)
+	{
+		LLStringUtil::format_map_t args;
+		args["[WHAT]"] = e.what();
+		std::string err = LLTrans::getString("fs_preprocessor_compress_regex_err", args);
+		LL_WARNS("FSLSLPreprocessor") << err << LL_ENDL;
+		display_error(err);
+		throw;
+	}
+	catch (std::exception& e)
+	{
+		LLStringUtil::format_map_t args;
+		args["[WHAT]"] = e.what();
+		std::string err = LLTrans::getString("fs_preprocessor_compress_exception", args);
+		LL_WARNS("FSLSLPreprocessor") << err << LL_ENDL;
+		display_error(err);
+		throw;
+	}
+	return script;
+}
+
+struct ProcCacheInfo
+{
+	LLViewerInventoryItem* item;
+	FSLSLPreprocessor* self;
+};
+
+class trace_include_files : public boost::wave::context_policies::default_preprocessing_hooks
+{
+public:
+	trace_include_files(FSLSLPreprocessor* proc)
+	:   mProc(proc) 
+	{
+		mAssetStack.push(LLUUID::null.asString());
+		mFileStack.push(proc->mMainScriptName);
+	}
+
+	template <typename ContextT>
+	bool found_include_directive(ContextT const& ctx, std::string const &filename, bool include_next)
+	{
+		std::string cfilename = filename.substr(1, filename.length() - 2);
+		LL_DEBUGS("FSLSLPreprocessor") << cfilename << ":found_include_directive" << LL_ENDL;
+		LLUUID item_id = FSLSLPreprocessor::findInventoryByName(cfilename);
+		if (item_id.notNull())
+		{
+			LLViewerInventoryItem* item = gInventory.getItem(item_id);
+			if (item)
+			{
+				std::map<std::string,LLUUID>::iterator it = mProc->cached_assetids.find(cfilename);
+				bool not_cached = (it == mProc->cached_assetids.end());
+				bool changed = true;
+				if (!not_cached)
+				{
+					changed = (mProc->cached_assetids[cfilename] != item->getAssetUUID());
+				}
+				if (not_cached || changed)
+				{
+					std::set<std::string>::iterator it = mProc->caching_files.find(cfilename);
+					if (it == mProc->caching_files.end())
+					{
+						if (not_cached)
+						{
+							LLStringUtil::format_map_t args;
+							args["[FILENAME]"] = cfilename;
+							mProc->display_message(LLTrans::getString("fs_preprocessor_cache_miss", args));
+						}
+						else /*if(changed)*/
+						{
+							LLStringUtil::format_map_t args;
+							args["[FILENAME]"] = cfilename;
+							mProc->display_message(LLTrans::getString("fs_preprocessor_cache_invalidated", args));
+						}
+						//one is always true
+						mProc->caching_files.insert(cfilename);
+						ProcCacheInfo* info = new ProcCacheInfo;
+						info->item = item;
+						info->self = mProc;
+						LLPermissions perm(((LLInventoryItem*)item)->getPermissions());
+						gAssetStorage->getInvItemAsset(LLHost(),
+														gAgent.getID(),
+														gAgent.getSessionID(),
+														perm.getOwner(),
+														LLUUID::null,
+														item->getUUID(),
+														LLUUID::null,
+														item->getType(),
+														&FSLSLPreprocessor::FSProcCacheCallback,
+														info,
+														TRUE);
+						return true;
+					}
+				}
+			}
+		}
+		else
+		{
+			//todo check on HDD in user defined dir for file in question
+		}
+		//++include_depth;
+		return false;
+	}
+
+	template <typename ContextT>
+	void opened_include_file(ContextT const& ctx, 
+		std::string const &relname, std::string const& absname,
+		bool is_system_include)
+	{
+		
+		ContextT& usefulctx = const_cast<ContextT&>(ctx);
+		std::string id;
+		std::string filename = boost::filesystem::path(relname).filename().string();
+		std::map<std::string,LLUUID>::iterator it = mProc->cached_assetids.find(filename);
+		if (it != mProc->cached_assetids.end())
+		{
+			id = mProc->cached_assetids[filename].asString();
+		}
+		else
+		{
+			id = "NOT_IN_WORLD";//I guess, still need to add external includes atm
+		}
+		mAssetStack.push(id);
+		std::string macro = "__ASSETID__";
+		usefulctx.remove_macro_definition(macro, true);
+		std::string def = llformat("%s=\"%s\"", macro.c_str(), id.c_str());
+		usefulctx.add_macro_definition(def, false);
+
+		mFileStack.push(filename);
+		macro = "__SHORTFILE__";
+		usefulctx.remove_macro_definition(macro, true);
+		def = llformat("%s=\"%s\"", macro.c_str(), filename.c_str());
+		usefulctx.add_macro_definition(def, false);
+	}
+
+
+	template <typename ContextT>
+	void returning_from_include_file(ContextT const& ctx)
+	{
+		ContextT& usefulctx = const_cast<ContextT&>(ctx);
+		if (mAssetStack.size() > 1)
+		{
+			mAssetStack.pop();
+			std::string id = mAssetStack.top();
+			std::string macro = "__ASSETID__";
+			usefulctx.remove_macro_definition(macro, true);
+			std::string def = llformat("%s=\"%s\"", macro.c_str(), id.c_str());
+			usefulctx.add_macro_definition(def, false);
+
+			mFileStack.pop();
+			std::string filename = mFileStack.top();
+			macro = "__SHORTFILE__";
+			usefulctx.remove_macro_definition(macro, true);
+			def = llformat("%s=\"%s\"", macro.c_str(), filename.c_str());
+			usefulctx.add_macro_definition(def, false);
+		}//else wave did something really wrong
+	}
+
+	template <typename ContextT, typename ExceptionT>
+	void throw_exception(ContextT const& ctx, ExceptionT const& e)
+	{
+		std::string err;
+		err = "warning: last line of file ends without a newline";
+		if (!err.compare( e.description()))
+		{
+			err = "Ignoring warning: ";
+			err += e.description();
+			LL_WARNS("FSLSLPreprocessor") << err << LL_ENDL;
+		}
+		else
+		{
+			boost::throw_exception(e);
+		}
+	}
+
+private:
+	FSLSLPreprocessor* mProc;
+	std::stack<std::string> mAssetStack;
+	std::stack<std::string> mFileStack;
+};
+
+void cache_script(const std::string& name, std::string content)
+{
+	content += "\n";/*hack!*/
+	LL_DEBUGS("FSLSLPreprocessor") << "writing " << name << " to cache" << LL_ENDL;
+	std::string path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "lslpreproc", name);
+	llofstream outstream(path);
+	if(outstream.is_open())
+	{
+		outstream.write(content.c_str(), content.length());
+	}
+}
+
+void FSLSLPreprocessor::FSProcCacheCallback(const LLUUID& iuuid, LLAssetType::EType type, void *userdata, S32 result, LLExtStat extstat)
+{
+	LLUUID uuid = iuuid;
+	LL_DEBUGS("FSLSLPreprocessor") << "cachecallback called" << LL_ENDL;
+	ProcCacheInfo* info = (ProcCacheInfo*)userdata;
+	LLViewerInventoryItem* item = info->item;
+	FSLSLPreprocessor* self = info->self;
+	if (item && self)
+	{
+		std::string name = item->getName();
+		if (result == LL_ERR_NOERR)
+		{
+			LLFileSystem file(uuid, type);
+			if (file.open())
+			{
+				S32 file_length = file.getSize();
+
+				std::string content;
+				content.resize(file_length + 1, 0);
+				file.read((U8*)&content[0], file_length);
+
+				content = utf8str_removeCRLF(content);
+				content = self->decode(content);
+				/*content += llformat("\n#define __UP_ITEMID__ __ITEMID__\n#define __ITEMID__ %s\n",uuid.asString().c_str())+content;
+				content += "\n#define __ITEMID__ __UP_ITEMID__\n";*/
+				//prolly wont work and ill have to be not lazy, but worth a try
+
+				if (boost::filesystem::native(name))
+				{
+					LL_DEBUGS("FSLSLPreprocessor") << "native name of " << name << LL_ENDL;
+					LLStringUtil::format_map_t args;
+					args["[FILENAME]"] = name;
+					self->display_message(LLTrans::getString("fs_preprocessor_cache_completed", args));
+					cache_script(name, content);
+					std::set<std::string>::iterator loc = self->caching_files.find(name);
+					if (loc != self->caching_files.end())
+					{
+						LL_DEBUGS("FSLSLPreprocessor") << "finalizing cache" << LL_ENDL;
+						self->caching_files.erase(loc);
+						//self->cached_files.insert(name);
+						if (uuid.isNull())uuid.generate();
+						item->setAssetUUID(uuid);
+						self->cached_assetids[name] = uuid;//.insert(uuid.asString());
+						self->start_process();
+					}
+					else
+					{
+						LL_DEBUGS("FSLSLPreprocessor") << "something went wrong" << LL_ENDL;
+					}
+				}
+				else
+				{
+					LLStringUtil::format_map_t args;
+					args["[FILENAME]"] = name;
+					self->display_error(LLTrans::getString("fs_preprocessor_cache_unsafe", args));
+				}
+			}
+		}
+		else
+		{
+			LLStringUtil::format_map_t args;
+			args["[FILENAME]"] = name;
+			self->display_error(LLTrans::getString("fs_preprocessor_caching_err", args));
+		}
+	}
+
+	if (info)
+	{
+		delete info;
+	}
+}
+
+void FSLSLPreprocessor::preprocess_script(BOOL close, bool sync, bool defcache)
+{
+	mClose = close;
+	mSync = sync;
+	mDefinitionCaching = defcache;
+	caching_files.clear();
+	LLStringUtil::format_map_t args;
+	display_message(LLTrans::getString("fs_preprocessor_starting"));
+	
+	LLFile::mkdir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"") + gDirUtilp->getDirDelimiter() + "lslpreproc");
+	std::string script = mCore->mEditor->getText();
+	if (mMainScriptName.empty())//more sanity
+	{
+		const LLInventoryItem* item = NULL;
+		LLPreview* preview = (LLPreview*)mCore->mUserdata;
+		if (preview)
+		{
+			item = preview->getItem();
+		}
+
+		if (item)
+		{
+			mMainScriptName = item->getName();
+		}
+		else
+		{
+			mMainScriptName = "(Unknown)";
+		}
+	}
+	const std::string& name = mMainScriptName;
+	cached_assetids[name] = LLUUID::null;
+	cache_script(name, script);
+	//start the party
+	start_process();
+}
+
+void FSLSLPreprocessor::preprocess_script(const LLUUID& asset_id, LLScriptQueueData* data, LLAssetType::EType type, const std::string& script_data)
+{
+	if(!data)
+	{
+		return;
+	}
+	
+	mScript = FSLSLPreprocessor::decode(script_data);
+	mAssetID = asset_id;
+	mData = data;
+	mType = type;
+	
+	mDefinitionCaching = false;
+	caching_files.clear();
+	LLStringUtil::format_map_t args;
+	display_message(LLTrans::getString("fs_preprocessor_starting"));
+	
+	LLFile::mkdir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"") + gDirUtilp->getDirDelimiter() + "lslpreproc");
+	
+	if (mData->mItem)
+	{
+		mMainScriptName = mData->mItem->getName();
+	}
+	else
+	{
+		mMainScriptName = "(Unknown)";
+	}
+	
+	const std::string& name = mMainScriptName;
+	cached_assetids[name] = LLUUID::null;
+	cache_script(name, mScript);
+	//start the party
+	start_process();
+}
+
+const std::string lazy_list_set_func("\
+list lazy_list_set(list L, integer i, list v)\n\
+{\n\
+    while (llGetListLength(L) < i)\n\
+        L = L + 0;\n\
+    return llListReplaceList(L, v, i, i);\n\
+}\n\
+");
+
+static void subst_lazy_references(std::string& script, std::string_view retype, std::string fn)
+{
+	std::string ref;
+	do
+	{
+		ref = script;
+
+		static std::map<std::string, boost::regex, std::less<>> lazy_ref_cache;
+		auto iter = lazy_ref_cache.find(retype);
+		if(iter == lazy_ref_cache.end())
+		{
+			boost::regex ref_regex(std::string(rDOT_MATCHES_NEWLINE
+				rCMNT_OR_STR "|"
+				"\\(" rOPT_SPC ) + std::string(retype) + std::string(rOPT_SPC "\\)" rOPT_SPC
+				// group 1: leading parenthesis
+				"(\\()?"
+				// group 2: identifier
+				rOPT_SPC "([a-zA-Z_][a-zA-Z0-9_]*+)"
+				rOPT_SPC "\\["
+				// group 3: subindex expression
+				"((?:"
+					rCMNT_OR_STR
+					// group 4: recursive bracketed expression
+					"|(\\[(?:" rCMNT_OR_STR "|[^][]|(?4))*+\\])" // recursive bracketed expression (e.g. []!=[])
+					"|[^][]" // or anything else
+				")+?)" // (non-greedy)
+				"\\]"
+				// group 5: trailing parenthesis
+				"(\\))?"
+				));
+			iter = lazy_ref_cache.emplace(retype, std::move(ref_regex)).first;
+		}
+		script = boost::regex_replace(script, iter->second,
+			// Boost supports conditions in format strings used in regex_replace.
+			// ?nX:Y means output X if group n matched, else output Y. $n means output group n.
+			// $& means output the whole match, which is used here to not alter the string.
+			// Parentheses are used for grouping; they have to be prefixed with \ to output them.
+			std::string("?2" // if group 2 matched, we have a (type)variable[index] to substitute
+			// if first paren is present, require the second (output the original text if not present)
+			"(?1(?5$1") + fn + std::string("\\($2,$3\\)$5:$&):")
+			// if first parent is not present, copy $5 verbatim (matched or not)
+			+ fn + std::string("\\($2,$3\\)$5):"
+			// if $2 didn't match, output whatever matched (string or comment)
+			"$&"), boost::format_all); // format_all enables these features
+	}
+	while (script != ref);
+}
+
+static std::string reformat_lazy_lists(const std::string& in_script)
+{
+	static const boost::regex lazy_list_regex(rDOT_MATCHES_NEWLINE
+		rCMNT_OR_STR
+		// exclude some keywords as possible identifiers that can
+		// be followed by an opening square bracket (FIRE-20278)
+		"|(?:return|do|else)(?![A-Za-z0-9_])"
+		// group 1: identifier
+		"|([a-zA-Z_][a-zA-Z0-9_]*+)" rOPT_SPC
+		// group 2: expression within brackets
+		"\\[((?:" rCMNT_OR_STR
+		// group 3: recursive bracketed expression
+		"|(\\[(?:" rCMNT_OR_STR "|[^][]|(?3))*+\\])" // recursive bracketed expression (e.g. []!=[])
+		"|[^][]" // or anything else
+		")++)\\]" rOPT_SPC
+		"=(?!=)" rOPT_SPC // = but not ==
+		// group 4: right-hand side expression
+		"((?:" rCMNT_OR_STR
+			// group 5: recursive parenthesized expression
+			"|(\\((?:" rCMNT_OR_STR "|[^()]|(?5))*+\\))" // recursive parenthesized expression
+			"|[^()]" // or anything else
+		")+?)" // non-greedy
+		"([;)])" // terminated only with a semicolon or a closing parenthesis
+		);
+	std::string script = boost::regex_replace(in_script, lazy_list_regex, "?1$1=lazy_list_set\\($1,$2,[$4]\\)$6:$&", boost::format_all);
+
+	// replace typed references followed by bracketed subindex with llList2XXXX,
+	// e.g. (rotation)mylist[3] is replaced with llList2Rot(mylist, (3))
+	subst_lazy_references(script, "integer", "llList2Integer");
+	subst_lazy_references(script, "float", "llList2Float");
+	subst_lazy_references(script, "string", "llList2String");
+	subst_lazy_references(script, "key", "llList2Key");
+	subst_lazy_references(script, "vector", "llList2Vector");
+	subst_lazy_references(script, "(?:rotation|quaternion)", "llList2Rot");
+	subst_lazy_references(script, "list", "llList2List");
+
+	// add lazy_list_set function to top of script
+	// (it can be overriden by a user function if the optimizer is active)
+	script = fmt::format(FMT_COMPILE("{}\n{}"), utf8str_removeCRLF(lazy_list_set_func), script);
+
+	return script;
+}
+
+
+static inline std::string randstr(S32 len, std::string_view chars)
+{
+	S32 clen = S32(chars.length());
+	S32 built = 0;
+	std::string ret;
+	while (built < len)
+	{
+		S32 r = std::rand() / ( RAND_MAX / clen );
+		r = r % clen;//sanity
+		ret += chars.at(r);
+		built += 1;
+	}
+	return ret;
+}
+
+static inline std::string quicklabel()
+{
+	return fmt::format(FMT_COMPILE("c{}"), randstr(5, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
+}
+
+static std::string reformat_switch_statements(std::string buffer, bool& lackDefault)
+{
+	try
+	{
+		static const boost::regex findswitches(rDOT_MATCHES_NEWLINE
+			rCMNT_OR_STR
+			"|" rSPC "++" // optimization to skip over blocks of whitespace faster
+			"|(?<![A-Za-z0-9_])(switch" rOPT_SPC "\\()"
+			"|."
+		);
+
+		boost::smatch matches;
+		std::string::const_iterator bstart = buffer.begin();
+
+		while (boost::regex_search(bstart, std::string::const_iterator(buffer.end()), matches, findswitches, boost::match_default))
+		{
+			if (matches[1].matched)
+			{
+				S32 res = std::distance(buffer.cbegin(), matches[1].first);
+
+				// slen excludes the "("
+				S32 slen = std::distance(matches[1].first, matches[1].second) - 1;
+
+				std::string arg = scopeript2(buffer, res + slen, '(', ')');
+
+				//arg *will have* () around it
+				if (arg == "begin out of bounds" || arg == "end out of bounds")
+				{
+					break;
+				}
+				LL_DEBUGS("FSLSLPreprocessor") << "arg=[" << arg << "]" << LL_ENDL;;
+				std::string rstate = scopeript2(buffer, res + slen + arg.length());
+				S32 cutlen = slen + arg.length() + rstate.length();
+
+				// Call recursively to process nested switch statements (FIRE-10517)
+				rstate = reformat_switch_statements(rstate, lackDefault);
+
+				//rip off the scope edges
+				S32 slicestart = rstate.find("{") + 1;
+				rstate = rstate.substr(slicestart, (rstate.rfind("}") - slicestart) - 1);
+				LL_DEBUGS("FSLSLPreprocessor") << "rstate=[" << rstate << "]" << LL_ENDL;
+
+				static const boost::regex findcases(rDOT_MATCHES_NEWLINE
+					rCMNT_OR_STR "|" rSPC "++|(?<![A-Za-z0-9_])(case" rREQ_SPC ")|.");
+
+				boost::smatch statematches;
+
+				std::map<std::string, std::string> ifs;
+				std::string::const_iterator rstart = rstate.begin();
+
+				while (boost::regex_search(rstart, std::string::const_iterator(rstate.end()), statematches, findcases, boost::match_default))
+				{
+					if (statematches[1].matched)
+					{
+						S32 case_start = std::distance(rstate.cbegin(), statematches[1].first);
+						S32 next_curl = rstate.find("{", case_start + 1);
+						S32 next_semi = rstate.find(":", case_start + 1);
+						S32 case_end = (next_semi == -1) ? next_curl :
+							(next_curl < next_semi&& next_curl != -1) ? next_curl : next_semi;
+						S32 caselen = std::distance(statematches[1].first, statematches[1].second);
+						if (case_end != -1)
+						{
+							std::string casearg = rstate.substr(case_start + caselen, case_end - (case_start + caselen));
+							LL_DEBUGS("FSLSLPreprocessor") << "casearg=[" << casearg << "]" << LL_ENDL;
+							std::string label = quicklabel();
+							ifs[casearg] = label;
+							LL_DEBUGS("FSLSLPreprocessor") << "BEFORE[" << rstate << "]" << LL_ENDL;
+							bool addcurl = (case_end == next_curl ? 1 : 0);
+							label = "@" + label + ";\n";
+							if (addcurl)
+							{
+								label += "{";
+							}
+							rstate.erase(case_start, (case_end - case_start) + 1);
+							rstate.insert(case_start, label);
+							LL_DEBUGS("FSLSLPreprocessor") << "AFTER[" << rstate << "]" << LL_ENDL;
+							rstart = rstate.begin() + (case_start + label.length());
+						}
+						else
+						{
+							LL_DEBUGS("FSLSLPreprocessor") << "error in regex case_end != -1" << LL_ENDL;
+							rstate.erase(case_start, caselen);
+							rstate.insert(case_start, "error; cannot find { or :");
+							rstart = rstate.begin() + (case_start + std::strlen("error; cannot find { or :"));
+						}
+					}
+					else
+					{
+						rstart = statematches[0].second;
+					}
+				}
+
+				std::string deflt = quicklabel();
+				bool hasdflt = false;
+				std::string defstate;
+
+				static const boost::regex defstate_regex(rDOT_MATCHES_NEWLINE
+					rCMNT_OR_STR "|" rSPC "++"
+					"|(?<![A-Za-z0-9_])(default)(?:" rOPT_SPC ":|(" rOPT_SPC "\\{))"
+					, boost::regex::perl);
+
+				defstate = boost::regex_replace(rstate, defstate_regex, "?1@" + deflt + ";$2:$&", boost::format_all);
+				if (defstate != rstate)
+				{
+					hasdflt = true;
+					rstate = defstate;
+				}
+				std::string argl;
+				std::string jumptable = "{";
+
+				std::map<std::string, std::string>::iterator ifs_it;
+				for (ifs_it = ifs.begin(); ifs_it != ifs.end(); ifs_it++)
+				{
+					jumptable += fmt::format(FMT_COMPILE("if({} == ({}))jump {};\n"), arg, ifs_it->first, ifs_it->second);
+				}
+				std::string brk = quicklabel();
+				if (!hasdflt)
+				{
+					// Add jump to break position if there's no default (FIRE-17710)
+					deflt = brk;
+					lackDefault = true;
+				}
+				jumptable += "jump " + deflt + ";\n";
+
+				rstate = jumptable + rstate + "\n";
+
+				static const boost::regex defstate_regex2(rDOT_MATCHES_NEWLINE
+					rCMNT_OR_STR "|"
+					"(?<![A-Za-z0-9_])break(" rOPT_SPC ";)"
+				);
+				defstate = boost::regex_replace(rstate, defstate_regex2, "?1jump " + brk + "$1:$&", boost::format_all);
+				if (defstate != rstate || !hasdflt)
+				{
+					rstate = defstate;
+					rstate += "\n@" + brk + ";\n";
+				}
+				rstate += "}";
+
+				LL_DEBUGS("FSLSLPreprocessor") << "replacing[" << buffer.substr(res, cutlen) << "] with [" << rstate << "]" << LL_ENDL;
+				buffer.erase(res, cutlen);
+				buffer.insert(res, rstate);
+
+				bstart = buffer.begin() + (res + rstate.length());
+
+			}
+			else /* not matches[1].matched */
+			{
+				// Found a token that is not "switch" - skip it
+				bstart = matches[0].second;
+			}
+		}
+	}
+	catch (...)
+	{
+		LL_WARNS("FSLSLPreprocessor") << "unexpected exception caught; buffer=[" << buffer << "]" << LL_ENDL;
+		throw;
+	}
+
+	return buffer;
+}
+
+void FSLSLPreprocessor::start_process()
+{
+	if (mWaving)
+	{
+		LL_WARNS("FSLSLPreprocessor") << "already waving?" << LL_ENDL;
+		return;
+	}
+
+	mWaving = true;
+	bool lackDefault = false;
+	boost::wave::util::file_position_type current_position;
+	std::string input;
+	if (mStandalone)
+	{
+		input = mScript;
+	}
+	else
+	{
+		input = mCore->mEditor->getText();
+	}
+	std::string rinput = input;
+	bool preprocessor_enabled = true;
+
+	// Simple check for the "do not preprocess" marker.  This logic will NOT survive a conversion into some form of sectional preprocessing as discussed in FIRE-9335, but will serve the basic use case given therein.
+	{
+		std::string::size_type location_index = rinput.find("//fspreprocessor off");
+		
+		if (location_index != std::string::npos)
+		{
+			std::string section_scanned = input.substr(0, location_index); // Used to compute the line number at which the marker was found.
+			LLStringUtil::format_map_t args;
+			args["[LINENUMBER]"] = llformat("%d", std::count(section_scanned.begin(), section_scanned.end(), '\n'));
+			display_message(LLTrans::getString("fs_preprocessor_disabled_by_script_marker", args));
+			preprocessor_enabled = false;
+		}
+	}
+
+	// Convert multiline strings for preprocessor
+	if (preprocessor_enabled)
+	{
+		std::ostringstream oaux;
+		// Simple DFA to parse the code for strings and comments,
+		// replacing newlines with '\n' inside strings so that the
+		// C preprocessor can interpret it correctly.
+		// states: 0=normal, 1=seen '"', 2=seen '"...\',
+		// 3=seen '/', 4=seen '/*', 5=seen '/*...*', 6=seen '//'
+		int state = 0;
+		int nlines = 0;
+		for (std::string::iterator it = input.begin(); it != input.end(); it++)
+		{
+			switch (state)
+			{
+				case 1: // inside string, no '\' seen last
+					if (*it == '\n')
+					{
+						// we're inside a string and detected a newline;
+						// replace with "\\n"
+						oaux << "\\n";
+						nlines++;
+						continue; // don't store the newline itself
+					}
+					else if (*it == '\\')
+					{
+						state = 2;
+					}
+					else if (*it == '"')
+					{
+						oaux << '"';
+						// add as many newlines as the string had,
+						// to respect original line numbers
+						while (nlines)
+						{
+							oaux << '\n';
+							nlines--;
+						}
+						state = 0;
+						continue;
+					}
+					break;
+				case 2: // inside string, '\' seen last
+					// just eat the escaped character
+					state = 1;
+					break;
+				case 3: // in code, '/' seen last
+					if (*it == '*')
+					{
+						state = 4; // multiline comment
+					}
+					else if (*it == '/')
+					{
+						state = 6; // single-line comment
+					}
+					else
+					{
+						state = 0; // it was just a slash
+					}
+					break;
+				case 4: // inside multiline comment, no '*' seen last
+					if (*it == '*')
+					{
+						state = 5;
+					}
+					break;
+				case 5: // inside multiline comment, '*' seen last
+					if (*it == '/')
+					{
+						state = 0;
+					}
+					else if (*it != '*')
+					{
+						state = 4;
+					}
+					break;
+				case 6: // inside single line comment ('//' style)
+					if (*it == '\n')
+					{
+						state = 0;
+					}
+					break;
+				default: // normal code
+					if (*it == '"')
+					{
+						state = 1;
+					}
+					else if (*it == '/')
+					{
+						state = 3;
+					}
+			}
+			oaux << *it;
+		}
+		input = oaux.str();
+	}
+	
+	//Make sure wave does not complain about missing newline at end of script.
+	input += "\n";
+	std::string output;
+	
+	std::string name = mMainScriptName;
+	static LLCachedControl<bool> lazy_lists_cc(gSavedSettings, "AlchemyPreProcLSLLazyLists");
+	static LLCachedControl<bool> use_switch_cc(gSavedSettings, "AlchemyPreProcLSLSwitch");
+	static LLCachedControl<bool> use_optimizer(gSavedSettings, "AlchemyPreProcLSLOptimizer");
+	static LLCachedControl<bool> enable_hdd_include(gSavedSettings, "AlchemyPreProcEnableHDDInclude");
+	static LLCachedControl<bool> use_compression(gSavedSettings, "AlchemyPreProcLSLTextCompress");
+	bool lazy_lists = lazy_lists_cc;
+	bool use_switch = use_switch_cc;
+	bool errored = false;
+	if (preprocessor_enabled)
+	{
+		std::string settings;
+		settings = LLTrans::getString("fs_preprocessor_settings_list_prefix") + " preproc";
+		if (lazy_lists)
+		{
+			settings = settings + " LazyLists";
+		}
+		if (use_switch)
+		{
+			settings = settings + " Switches";
+		}
+		if (use_optimizer)
+		{
+			settings = settings + " Optimize";
+		}
+		if (enable_hdd_include)
+		{
+			settings = settings + " HDDInclude";
+		}
+		if (use_compression)
+		{
+			settings = settings + " Compress";
+		}
+		//display the settings
+		display_message(settings);
+
+		LL_DEBUGS("FSLSLPreprocessor") << settings << LL_ENDL;
+		std::string err;
+		try
+		{
+			trace_include_files tracer(this);
+			typedef boost::wave::cpplexer::lex_token<> token_type;
+			typedef boost::wave::cpplexer::lex_iterator<token_type> lex_iterator_type;
+			typedef boost::wave::context<std::string::iterator, lex_iterator_type, boost::wave::iteration_context_policies::load_file_to_string, trace_include_files >
+					context_type;
+
+			context_type ctx(input.begin(), input.end(), name.c_str(), tracer);
+			ctx.set_language(boost::wave::enable_long_long(ctx.get_language()));
+			ctx.set_language(boost::wave::enable_prefer_pp_numbers(ctx.get_language()));
+			ctx.set_language(boost::wave::enable_variadics(ctx.get_language()));
+			
+			std::string path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"") + gDirUtilp->getDirDelimiter() + "lslpreproc" + gDirUtilp->getDirDelimiter();
+			ctx.add_include_path(path.c_str());
+			if (enable_hdd_include)
+			{
+				std::string hddpath = gSavedSettings.getString("AlchemyPreProcHDDIncludeLocation");
+				if (!hddpath.empty())
+				{
+					ctx.add_include_path(hddpath.c_str());
+					ctx.add_sysinclude_path(hddpath.c_str());
+				}
+			}
+			std::string def = llformat("__AGENTKEY__=\"%s\"", gAgentID.asString().c_str());//legacy because I used it earlier
+			ctx.add_macro_definition(def, false);
+			def = llformat("__AGENTID__=\"%s\"", gAgentID.asString().c_str());
+			ctx.add_macro_definition(def, false);
+			def = llformat("__AGENTIDRAW__=%s", gAgentID.asString().c_str());
+			ctx.add_macro_definition(def, false);
+			std::string aname = gAgentAvatarp->getFullname();
+			def = llformat("__AGENTNAME__=\"%s\"", aname.c_str());
+			ctx.add_macro_definition(def, false);
+			def = llformat("__ASSETID__=%s", LLUUID::null.asString().c_str());
+			ctx.add_macro_definition(def, false);
+			def = llformat("__SHORTFILE__=\"%s\"", name.c_str());
+			ctx.add_macro_definition(def, false);
+			def = llformat("__UNIXTIME__=%i", (S32)time_corrected());
+			ctx.add_macro_definition(def, false);
+
+			ctx.add_macro_definition("list(...)=((list)(__VA_ARGS__))", false);
+			ctx.add_macro_definition("float(...)=((float)(__VA_ARGS__))", false);
+			ctx.add_macro_definition("integer(...)=((integer)(__VA_ARGS__))", false);
+			ctx.add_macro_definition("key(...)=((key)(__VA_ARGS__))", false);
+			ctx.add_macro_definition("rotation(...)=((rotation)(__VA_ARGS__))", false);
+			ctx.add_macro_definition("quaternion(...)=((quaternion)(__VA_ARGS__))", false);
+			ctx.add_macro_definition("string(...)=((string)(__VA_ARGS__))", false);
+			ctx.add_macro_definition("vector(...)=((vector)(__VA_ARGS__))", false);
+
+			context_type::iterator_type first = ctx.begin();
+			context_type::iterator_type last = ctx.end();
+
+			while (first != last)
+			{
+				if (caching_files.size() != 0)
+				{
+					mWaving = false;
+					return;
+				}
+				current_position = (*first).get_position();
+				
+				std::string token = std::string((*first).get_value().c_str());//stupid boost bitching even though we know its a std::string
+				
+				if (token == "#line")
+				{
+					token = "//#line";
+				}
+
+				output += token;
+				
+				if (!lazy_lists)
+				{
+					lazy_lists = ctx.is_defined_macro(std::string("USE_LAZY_LISTS"));
+				}
+				
+				if (!use_switch)
+				{
+					use_switch = ctx.is_defined_macro(std::string("USE_SWITCHES"));
+				}
+				++first;
+			}
+		}
+		catch(boost::wave::cpp_exception const& e)
+		{
+			errored = true;
+			// some preprocessing error
+			LLStringUtil::format_map_t args;
+			args["[ERR_NAME]"] = e.file_name();
+			args["[LINENUMBER]"] = llformat("%d", e.line_no() - 1);
+			args["[ERR_DESC]"] = e.description();
+			std::string err = LLTrans::getString("fs_preprocessor_cpp_exception", args);
+			LL_WARNS("FSLSLPreprocessor") << err << LL_ENDL;
+			display_error(err);
+		}
+		catch(boost::wave::cpplexer::lexing_exception const& e)
+		{
+			// lexing preprocessing error
+			boost::wave::cpplexer::util::severity severity_level = e.severity_level(e.get_errorcode());
+			errored = (severity_level != boost::wave::cpplexer::util::severity_warning && severity_level != boost::wave::cpplexer::util::severity_remark);
+			LLStringUtil::format_map_t args;
+			std::string severity_text = e.severity_text(e.get_errorcode());
+			LLStringUtil::toUpper(severity_text);
+			args["[SEVERITY]"] = severity_text;
+			args["[ERR_NAME]"] = e.file_name();
+			args["[LINENUMBER]"] = llformat("%d", e.line_no() - 1);
+			args["[ERR_DESC]"] = e.description();
+			std::string err = LLTrans::getString("fs_preprocessor_lexing_exception", args);
+			LL_WARNS("FSLSLPreprocessor") << err << LL_ENDL;
+			display_error(err);
+		}
+		catch(std::exception const& e)
+		{
+			errored = true;
+			LLStringUtil::format_map_t args;
+			args["[ERR_NAME]"] = std::string(current_position.get_file().c_str());
+			args["[LINENUMBER]"] = llformat("%d", current_position.get_line());
+			args["[ERR_DESC]"] = e.what();
+			display_error(LLTrans::getString("fs_preprocessor_exception", args));
+		}
+		catch (...)
+		{
+			errored = true;
+			LLStringUtil::format_map_t args;
+			args["[ERR_NAME]"] = std::string(current_position.get_file().c_str());
+			args["[LINENUMBER]"] = llformat("%d", current_position.get_line());
+			std::string err = LLTrans::getString("fs_preprocessor_error", args);
+			LL_WARNS("FSLSLPreprocessor") << err << LL_ENDL;
+			display_error(err);
+		}
+	}
+	
+	if (preprocessor_enabled && !errored)
+	{
+		if (lazy_lists)
+		{
+			try
+			{
+				display_message(LLTrans::getString("fs_preprocessor_lazylist_start"));
+				try
+				{
+					output = reformat_lazy_lists(output);
+				}
+				catch (boost::regex_error& e)
+				{
+					LLStringUtil::format_map_t args;
+					args["[WHAT]"] = e.what();
+					std::string err = LLTrans::getString("fs_preprocessor_lazylist_regex_err", args);
+					LL_WARNS("FSLSLPreprocessor") << err << LL_ENDL;
+					display_error(err);
+					throw;
+				}
+				catch (std::exception& e)
+				{
+					LLStringUtil::format_map_t args;
+					args["[WHAT]"] = e.what();
+					std::string err = LLTrans::getString("fs_preprocessor_lazylist_exception", args);
+					LL_WARNS("FSLSLPreprocessor") << err << LL_ENDL;
+					display_error(err);
+					throw;
+				}
+			}
+			catch(...)
+			{
+				errored = true;
+				display_error(LLTrans::getString("fs_preprocessor_lazylist_unexpected_exception"));
+			}
+		}
+
+		if (use_switch)
+		{
+			try
+			{
+				display_message(LLTrans::getString("fs_preprocessor_switchstatement_start"));
+				try
+				{
+					output = reformat_switch_statements(output, lackDefault);
+				}
+				catch (boost::regex_error& e)
+				{
+					LLStringUtil::format_map_t args;
+					args["[WHAT]"] = e.what();
+					std::string err = LLTrans::getString("fs_preprocessor_switchstatement_regex_err", args);
+					LL_WARNS("FSLSLPreprocessor") << err << LL_ENDL;
+					display_error(err);
+					throw;
+				}
+				catch (std::exception& e)
+				{
+					LLStringUtil::format_map_t args;
+					args["[WHAT]"] = e.what();
+					std::string err = LLTrans::getString("fs_preprocessor_switchstatement_exception", args);
+					LL_WARNS("FSLSLPreprocessor") << err << LL_ENDL;
+					display_error(err);
+					throw;
+				}
+			}
+			catch(...)
+			{
+				errored = true;
+				display_error(LLTrans::getString("fs_preprocessor_switchstatement_unexpected_exception"));
+			}
+		}
+	}
+
+	if (!mDefinitionCaching)
+	{
+		if (!errored)
+		{
+			if (preprocessor_enabled && use_optimizer)
+			{
+				display_message(LLTrans::getString("fs_preprocessor_optimizer_start"));
+				try
+				{
+					output = lslopt(output);
+				}
+				catch(...)
+				{	
+					errored = true;
+					display_error(LLTrans::getString("fs_preprocessor_optimizer_unexpected_exception"));
+				}
+			}
+		}
+		else
+		{
+			// FIRE-31718: Preprocessor crashes viewer on recursive #include
+
+			// Truncate the resulting preprocessed script to something the text field can handle without
+			// freezing for so long the viewer disconnects. The usual script source code limit is 64kB so
+			// let's play it safe and allow twice as much here. The script is most likely already unusable
+			// at this point due to the preprocessor bailing out with an error earlier, so a truncated
+			// version doesn't hurt more than it already did.
+			if (output.size() > 128 * 1024)
+			{
+				output.resize(128 * 1024);
+				display_error(LLTrans::getString("fs_preprocessor_truncated"));
+			}
+		}
+
+		if (!errored)
+		{
+			if (preprocessor_enabled && use_compression)
+			{
+				display_message(LLTrans::getString("fs_preprocessor_compress_exception"));
+				try
+				{
+					output = lslcomp(output);
+				}
+				catch(...)
+				{
+					errored = true;
+					display_error(LLTrans::getString("fs_preprocessor_compress_unexpected_exception"));
+				}
+			}
+		}
+		
+		if (preprocessor_enabled)
+		{
+			output = encode(rinput) + "\n\n" + output;
+		}
+		else
+		{
+			output = rinput;
+		}
+
+		if (mStandalone)
+		{
+			LLFloaterCompileQueue::scriptPreprocComplete(mAssetID, mData, mType, output);
+		}
+		else
+		{
+			FSLSLPreProcViewer* outfield = mCore->mPostEditor;
+			if (outfield)
+			{
+				outfield->setText(LLStringExplicit(output));
+			}
+			mCore->mPostScript = output;
+			mCore->enableSave(TRUE); // The preprocessor run forces a change. (For FIRE-10173) -Sei
+			mCore->doSaveComplete((void*)mCore, mClose, mSync);
+		}
+	}
+	//if (lackDefault)
+	//{
+	//	LLNotificationsUtil::add("DefaultLabelMissing");
+	//}
+	mWaving = false;
+}
+
+void FSLSLPreprocessor::display_message(const std::string& err)
+{
+	if (mStandalone)
+	{
+		LLFloaterCompileQueue::scriptLogMessage(mData, err);
+	}
+	else
+	{
+		mCore->mErrorList->setCommentText(err);
+	}
+}
+
+void FSLSLPreprocessor::display_error(const std::string& err)
+{
+	if (mStandalone)
+	{
+		LLFloaterCompileQueue::scriptLogMessage(mData, err);
+	}
+	else
+	{
+		LLSD row;
+		row["columns"][0]["value"] = err;
+		row["columns"][0]["font"] = "SANSSERIF_SMALL";
+		mCore->mErrorList->addElement(row);
+	}
+}
+
+
+bool FSLSLPreprocessor::mono_directive(std::string const& text, bool agent_inv)
+{
+	bool domono = agent_inv;
+	
+	if (text.find("//mono\n") != std::string::npos)
+	{
+		domono = true;
+	}
+	else if (text.find("//lsl2\n") != std::string::npos)
+	{
+		domono = false;
+	}
+	return domono;
+}
diff --git a/indra/newview/fslslpreproc.h b/indra/newview/fslslpreproc.h
new file mode 100644
index 0000000000000000000000000000000000000000..61ebe50a33b2dadb8d7501f6e29acc6a8046162c
--- /dev/null
+++ b/indra/newview/fslslpreproc.h
@@ -0,0 +1,106 @@
+/**
+ * @file fslslpreproc.h
+ * Copyright (c) 2010
+ *
+ * Modular Systems All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *   3. Neither the name Modular Systems nor the names of its contributors
+ *      may be used to endorse or promote products derived from this
+ *      software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MODULAR SYSTEMS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MODULAR SYSTEMS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FS_LSLPREPROC_H
+#define FS_LSLPREPROC_H
+
+#include "llviewerprecompiledheaders.h"
+#include "llpreviewscript.h"
+
+#define DARWINPREPROC
+//force preproc on mac
+
+struct LLScriptQueueData;
+
+class FSLSLPreprocessor
+{
+	LOG_CLASS(FSLSLPreprocessor);
+public:
+
+	FSLSLPreprocessor(LLScriptEdCore* corep)
+		: mCore(corep), mWaving(false), mClose(FALSE), mSync(false), mStandalone(false)
+	{}
+	
+	FSLSLPreprocessor()
+		: mWaving(false), mClose(FALSE), mSync(false), mStandalone(true)
+	{}
+
+	static bool mono_directive(std::string const& text, bool agent_inv = true);
+	std::string encode(const std::string& script);
+	std::string decode(const std::string& script);
+
+	std::string lslopt(std::string script);
+	std::string lslcomp(std::string script);
+
+	static LLUUID findInventoryByName(std::string name);
+	static void FSProcCacheCallback(const LLUUID& uuid, LLAssetType::EType type,
+									void *userdata, S32 result, LLExtStat extstat);
+	void preprocess_script(BOOL close = FALSE, bool sync = false, bool defcache = false);
+	void preprocess_script(const LLUUID& asset_id, LLScriptQueueData* data, LLAssetType::EType type, const std::string& script_data);
+	void start_process();
+	void display_message(const std::string& err);
+	void display_error(const std::string& err);
+
+	//dual function, determines if files have been modified this session and if we have cached them
+	//also assetids exposed in-preprocessing as a predefined macro for use in include once style include files, e.g. #define THISFILE file_ ## __ASSETIDRAW__
+	//in case it isn't obvious, the viewer only sets the asset id on a successful script save (of a full perm script), or in preproc on-cache
+	//so this is only applicable to fully permissive scripts; which is just fine, since if it isn't full perm it isn't really useful as a include anyway.
+	//in the event of a no-trans script (only less than full thats readable), the server sends null key, and we will set a random uuid. 
+	//This uuid should be overwritten if they edit that script, whether with the real id or null key is irrelevant in this case.
+	//theoretically, if the asset IDs were exposed for full perm scripts without downloading the script at least once, it would save unnecessary caching
+	//as this isn't the case I'm not going to preserve this structure across logins.
+
+	//(it seems rather dumb that readable scripts don't show the asset id without a DL, but thats beside the point.)
+	static std::map<std::string, LLUUID> cached_assetids;
+
+	static std::map<std::string, std::string> decollided_literals;
+
+	std::set<std::string> caching_files;
+	std::set<std::string> defcached_files;
+	bool mDefinitionCaching;
+
+	LLScriptEdCore* mCore;
+	bool mWaving;
+	BOOL mClose;
+	bool mSync;
+	std::string mMainScriptName;
+	
+	// Compile queue
+	bool mStandalone;
+	std::string mScript;
+	LLUUID mAssetID;
+	LLScriptQueueData* mData;
+	LLAssetType::EType mType;
+};
+
+#endif // FS_LSLPREPROC_H
diff --git a/indra/newview/fslslpreprocviewer.cpp b/indra/newview/fslslpreprocviewer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..24e7edeb5ac4be52b8d99c71ae3f37819dcdaefb
--- /dev/null
+++ b/indra/newview/fslslpreprocviewer.cpp
@@ -0,0 +1,57 @@
+/** 
+ * @file fslslpreprocviewer.cpp
+ * @brief Specialized LLScriptEditor class for displaying LSL preprocessor output
+ *
+ * $LicenseInfo:firstyear=2016&license=viewerlgpl$
+ * Phoenix Firestorm Viewer Source Code
+ * Copyright (c) 2016 Ansariel Hiller @ Second Life
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
+ * http://www.firestormviewer.org
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "fslslpreprocviewer.h"
+
+static LLDefaultChildRegistry::Register<FSLSLPreProcViewer> r("lsl_preproc_viewer");
+
+FSLSLPreProcViewer::FSLSLPreProcViewer(const Params& p)
+:	LLScriptEditor(p)
+{
+}
+
+BOOL FSLSLPreProcViewer::handleKeyHere(KEY key, MASK mask )
+{
+	// Normal key handling
+	BOOL handled = handleNavigationKey( key, mask )
+					|| handleSelectionKey(key, mask)
+					|| handleControlKey(key, mask);
+
+	if (handled)
+	{
+		resetCursorBlink();
+		needsScroll();
+	}
+
+	return handled;
+}
+
+BOOL FSLSLPreProcViewer::handleUnicodeCharHere(llwchar uni_char)
+{
+	return FALSE;
+}
diff --git a/indra/newview/fslslpreprocviewer.h b/indra/newview/fslslpreprocviewer.h
new file mode 100644
index 0000000000000000000000000000000000000000..bccf2b33e28515e41c8c0903bacbe724277dd025
--- /dev/null
+++ b/indra/newview/fslslpreprocviewer.h
@@ -0,0 +1,60 @@
+/** 
+ * @file fslslpreprocviewer.h
+ * @brief Specialized LLScriptEditor class for displaying LSL preprocessor output
+ *
+ * $LicenseInfo:firstyear=2016&license=viewerlgpl$
+ * Phoenix Firestorm Viewer Source Code
+ * Copyright (c) 2016 Ansariel Hiller @ Second Life
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
+ * http://www.firestormviewer.org
+ * $/LicenseInfo$
+ */
+
+#ifndef FS_LSLPREPROCVIEWER_H
+#define FS_LSLPREPROCVIEWER_H
+
+#include "llscripteditor.h"
+
+class FSLSLPreProcViewer : public LLScriptEditor
+{
+public:
+	
+	struct Params : public LLInitParam::Block<Params, LLScriptEditor::Params>
+	{
+		Params()
+		{}
+	};
+	
+	virtual ~FSLSLPreProcViewer() = default;
+
+	virtual BOOL	handleKeyHere(KEY key, MASK mask );
+	virtual BOOL	handleUnicodeCharHere(llwchar uni_char);
+
+	virtual BOOL	canCut() const { return false; }
+	virtual BOOL	canPaste() const { return false; }
+	virtual BOOL	canUndo() const { return false; }
+	virtual BOOL	canRedo() const { return false; }
+	virtual BOOL	canPastePrimary() const { return false; }
+	virtual BOOL	canDoDelete() const { return false; }
+
+protected:
+	friend class LLUICtrlFactory;
+	FSLSLPreProcViewer(const Params& p);
+};
+
+#endif // FS_LSLPREPROCVIEWER_H
diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp
index a5c9400ed25f47cf846c75dcbb885b6be32a4063..9a0b570986ba9d025660dcb771aed6af443120fc 100644
--- a/indra/newview/llcompilequeue.cpp
+++ b/indra/newview/llcompilequeue.cpp
@@ -53,6 +53,7 @@
 #include "lldir.h"
 #include "llnotificationsutil.h"
 #include "llviewerstats.h"
+#include "llfilesystem.h"
 #include "lluictrlfactory.h"
 #include "lltrans.h"
 
@@ -62,6 +63,9 @@
 #include "llviewerassetupload.h"
 #include "llcorehttputil.h"
 
+#include "fslslpreproc.h"
+#include "llsdutil.h"
+
 namespace
 {
 
@@ -102,14 +106,19 @@ namespace
     class HandleScriptUserData
     {
     public:
-        HandleScriptUserData(const std::string &pumpname) :
-            mPumpname(pumpname)
+        HandleScriptUserData(const std::string &pumpname, LLScriptQueueData* data) :
+            mPumpname(pumpname),
+            mData(data)
         { }
+        HandleScriptUserData() = default;
 
         const std::string &getPumpName() const { return mPumpname; }
 
+        LLScriptQueueData* getData() const { return mData; }
+
     private:
         std::string mPumpname;
+        LLScriptQueueData* mData;
     };
 
 
@@ -159,23 +168,6 @@ class LLQueuedScriptAssetUpload : public LLScriptAssetUpload
     std::string mScriptName;
 };
 
-///----------------------------------------------------------------------------
-/// Local function declarations, constants, enums, and typedefs
-///----------------------------------------------------------------------------
-
-struct LLScriptQueueData
-{
-	LLUUID mQueueID;
-	LLUUID mTaskId;
-	LLPointer<LLInventoryItem> mItem;
-	LLHost mHost;
-	LLUUID mExperienceId;
-	std::string mExperiencename;
-	LLScriptQueueData(const LLUUID& q_id, const LLUUID& task_id, LLInventoryItem* item) :
-		mQueueID(q_id), mTaskId(task_id), mItem(new LLInventoryItem(item)) {}
-
-};
-
 ///----------------------------------------------------------------------------
 /// Class LLFloaterScriptQueue
 ///----------------------------------------------------------------------------
@@ -256,6 +248,10 @@ LLFloaterCompileQueue::LLFloaterCompileQueue(const LLSD& key)
 	setTitle(LLTrans::getString("CompileQueueTitle"));
 	setStartString(LLTrans::getString("CompileQueueStart"));
 														 															 
+	if(gSavedSettings.getBOOL("AlchemyLSLPreprocessor"))
+	{
+		mLSLProc = std::make_unique<FSLSLPreprocessor>();
+	}
 }
 
 LLFloaterCompileQueue::~LLFloaterCompileQueue()
@@ -311,6 +307,30 @@ void LLFloaterCompileQueue::handleScriptRetrieval(const LLUUID& assetId,
         {
             result["message"] = LLTrans::getString("CompileQueueUnknownFailure");
         }
+
+        delete ((HandleScriptUserData *)userData)->getData();
+    }
+    else if (gSavedSettings.getBOOL("AlchemyLSLPreprocessor"))
+    {
+        LLScriptQueueData* data = ((HandleScriptUserData *)userData)->getData();
+        LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", data->mQueueID);
+
+        if (queue && queue->mLSLProc)
+        {
+            LLFileSystem file(assetId, type);
+			if (file.open())
+			{
+				S32 file_length = file.getSize();
+				std::vector<char> script_data(file_length + 1);
+				file.read((U8*)&script_data[0], file_length);
+				// put a EOS at the end
+				script_data[file_length] = 0;
+
+				queue->addProcessingMessage("CompileQueuePreprocessing", LLSD().with("SCRIPT", data->mItem->getName()));
+				queue->mLSLProc->preprocess_script(assetId, data, type, LLStringExplicit(&script_data[0]));
+			}
+        }
+        result["preproc"] = true;
     }
 
     LLEventPumps::instance().post(((HandleScriptUserData *)userData)->getPumpName(), result);
@@ -427,8 +447,17 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
     }
 
     {
-        HandleScriptUserData    userData(pump.getName());
-
+        HandleScriptUserData userData;
+        if (gSavedSettings.getBOOL("AlchemyLSLPreprocessor"))
+        {
+            // Need to dump some stuff into an LLScriptQueueData struct for the LSL PreProc.
+            LLScriptQueueData* datap = new LLScriptQueueData(hfloater.get()->getKey().asUUID(), object->getID(), experienceId, item);
+            userData = HandleScriptUserData(pump.getName(), datap);
+        }
+        else
+        {
+            userData = HandleScriptUserData(pump.getName(), NULL);
+        }
 
         // request the asset
         gAssetStorage->getInvItemAsset(LLHost(),
@@ -470,6 +499,12 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
         return true;
     }
 
+    if (result.has("preproc"))
+    {
+        // LSL Preprocessor handles it from here on
+        return true;
+    }
+
     LLUUID assetId = result["asset_id"];
 
     std::string url = object->getRegion()->getCapability("UpdateScriptTask");
@@ -884,3 +919,135 @@ void LLFloaterScriptQueue::objectScriptProcessingQueueCoro(std::string action, L
         LL_DEBUGS("SCRIPTQ") << "LLExeceptionStaleHandle caught! Floater has most likely been closed." << LL_ENDL;
     }
 }
+
+class LLScriptAssetUploadWithId: public LLScriptAssetUpload
+{
+public:
+	LLScriptAssetUploadWithId(	LLUUID taskId, LLUUID itemId, TargetType_t targetType, 
+		bool isRunning, std::string scriptName, LLUUID queueId, LLUUID exerienceId, std::string buffer, taskUploadFinish_f finish )
+		:  LLScriptAssetUpload( taskId, itemId, targetType,  isRunning, exerienceId, buffer, finish),
+		mScriptName(scriptName),
+        mQueueId(queueId)
+	{
+	}
+
+    virtual LLSD prepareUpload()
+    {
+        LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", LLSD(mQueueId));
+        if (queue)
+        {
+            LLStringUtil::format_map_t args;
+            args["OBJECT_NAME"] = getScriptName();
+            std::string message = queue->getString("Compiling", args);
+
+            queue->addStringMessage(message);
+        }
+
+        return LLBufferedAssetUploadInfo::prepareUpload();
+    }
+
+    std::string getScriptName() const { return mScriptName; }
+
+private:
+    void setScriptName(const std::string &scriptName) { mScriptName = scriptName; }
+
+    LLUUID mQueueId;
+    std::string mScriptName;
+};
+
+/*static*/
+void LLFloaterCompileQueue::finishLSLUpload(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, std::string scriptName, LLUUID queueId)
+{
+    LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", LLSD(queueId));
+    if (queue)
+    {
+        // Bytecode save completed
+        if (response["compiled"])
+        {
+            std::string message = std::string("Compilation of \"") + scriptName + std::string("\" succeeded");
+            LL_INFOS() << message << LL_ENDL;
+            LLStringUtil::format_map_t args;
+            args["OBJECT_NAME"] = scriptName;
+            queue->addStringMessage(queue->getString("CompileSuccess", args));
+        }
+        else
+        {
+            LLSD compile_errors = response["errors"];
+            for (LLSD::array_const_iterator line = compile_errors.beginArray();
+                line < compile_errors.endArray(); line++)
+            {
+                std::string str = line->asString();
+                str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
+                queue->addStringMessage(str);
+            }
+            LL_INFOS() << response["errors"] << LL_ENDL;
+        }
+    }
+}
+
+// This is the callback after the script has been processed by preproc
+// static
+void LLFloaterCompileQueue::scriptPreprocComplete(const LLUUID& asset_id, LLScriptQueueData* data, LLAssetType::EType type, const std::string& script_text)
+{
+	LL_INFOS() << "LLFloaterCompileQueue::scriptPreprocComplete()" << LL_ENDL;
+	if (!data)
+	{
+		return;
+	}
+	LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", data->mQueueID);
+	
+	if (queue)
+	{
+		std::string filename;
+		std::string uuid_str;
+		asset_id.toString(uuid_str);
+		filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str) + llformat(".%s",LLAssetType::lookup(type));
+		
+		const bool is_running = true;
+		LLViewerObject* object = gObjectList.findObject(data->mTaskId);
+		if (object)
+		{
+			std::string scriptName = data->mItem->getName();
+			std::string url = object->getRegion()->getCapability("UpdateScriptTask");
+			if (!url.empty())
+			{
+				queue->addProcessingMessage("CompileQueuePreprocessingComplete", LLSD().with("SCRIPT", scriptName));
+
+				LLBufferedAssetUploadInfo::taskUploadFinish_f proc = boost::bind(&LLFloaterCompileQueue::finishLSLUpload, _1, _2, _3, _4, 
+					scriptName, data->mQueueID);
+
+				LLResourceUploadInfo::ptr_t uploadInfo( new LLScriptAssetUploadWithId(
+					data->mTaskId,
+					data->mItem->getUUID(),
+					(queue->mMono) ? LLScriptAssetUpload::MONO : LLScriptAssetUpload::LSL2,
+					is_running,
+					scriptName,
+					data->mQueueID,
+					data->mExperienceId,
+					script_text,
+					proc));
+
+				LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
+			}
+			else
+			{
+				queue->addStringMessage(LLTrans::getString("CompileQueueServiceUnavailable"));
+			}
+		}
+	}
+	delete data;
+}
+
+// static
+void LLFloaterCompileQueue::scriptLogMessage(LLScriptQueueData* data, std::string message)
+{
+	if (!data)
+	{
+		return;
+	}
+	LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", data->mQueueID);
+	if (queue)
+	{
+		queue->addStringMessage(message);
+	}
+}
diff --git a/indra/newview/llcompilequeue.h b/indra/newview/llcompilequeue.h
index 2d0886c3da64ee4c77907d464be7881845cab5d2..472cd61dc7dd81cadb45edb6d6416715208e2f17 100644
--- a/indra/newview/llcompilequeue.h
+++ b/indra/newview/llcompilequeue.h
@@ -36,6 +36,25 @@
 #include "llevents.h"
 
 class LLScrollListCtrl;
+class FSLSLPreprocessor;
+
+struct LLScriptQueueData
+{
+	LLUUID mQueueID;
+	LLUUID mTaskId;
+	LLPointer<LLInventoryItem> mItem;
+	LLUUID mExperienceId;
+	std::string mExperiencename;
+
+	LLScriptQueueData(const LLUUID& q_id, const LLUUID& task_id, const LLUUID& experience_id, LLInventoryItem* item) :
+		mQueueID(q_id),
+		mTaskId(task_id),
+		mExperienceId(experience_id),
+		mItem(new LLInventoryItem(item))
+	{ }
+
+};
+// </FS:KC>
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLFloaterScriptQueue
@@ -126,6 +145,9 @@ class LLFloaterCompileQueue final : public LLFloaterScriptQueue
 	void experienceIdsReceived( const LLSD& content );
 	BOOL hasExperience(const LLUUID& id)const;
 
+	static void finishLSLUpload(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, std::string scriptName, LLUUID queueId);
+	static void scriptPreprocComplete(const LLUUID& asset_id, LLScriptQueueData* data, LLAssetType::EType type, const std::string& script_text);
+	static void scriptLogMessage(LLScriptQueueData* data, std::string message);
 protected:
 	LLFloaterCompileQueue(const LLSD& key);
 	virtual ~LLFloaterCompileQueue();
@@ -142,6 +164,8 @@ class LLFloaterCompileQueue final : public LLFloaterScriptQueue
     static void processExperienceIdResults(LLSD result, LLUUID parent);
     //uuid_list_t mAssetIds;  // list of asset IDs processed.
 	uuid_list_t mExperienceIds;
+
+	std::unique_ptr<FSLSLPreprocessor> mLSLProc;
 };
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/indra/newview/llfloatergotoline.cpp b/indra/newview/llfloatergotoline.cpp
index ad690b4ad5a6dc0e136817807d878183ea3d0615..3d18a27f12273a8314f11d17d0b37d661e829e77 100644
--- a/indra/newview/llfloatergotoline.cpp
+++ b/indra/newview/llfloatergotoline.cpp
@@ -107,14 +107,14 @@ void LLFloaterGotoLine::handleBtnGoto()
         row = getChild<LLUICtrl>("goto_line")->getValue().asInteger();
         if (row >= 0)
         {
-                if (mEditorCore && mEditorCore->mEditor)
+                if (mEditorCore && mEditorCore->mCurrentEditor)
                 {
-			mEditorCore->mEditor->deselect();
+			mEditorCore->mCurrentEditor->deselect();
 // [SL:KB] - Patch: UI-ScriptGoToLine | Checked: 2013-12-31 (Catznip-3.6)
-			mEditorCore->mEditor->scrollTo(row, column);
+			mEditorCore->mCurrentEditor->scrollTo(row, column);
 // [/SL:KB]
-//			mEditorCore->mEditor->setCursor(row, column);
-			mEditorCore->mEditor->setFocus(TRUE);
+//			mEditorCore->mCurrentEditor->setCursor(row, column);
+			mEditorCore->mCurrentEditor->setFocus(TRUE);
                 }
         }
 }
@@ -145,20 +145,20 @@ void LLFloaterGotoLine::onGotoBoxCommit()
         row = getChild<LLUICtrl>("goto_line")->getValue().asInteger();
         if (row >= 0)
         {
-                if (mEditorCore && mEditorCore->mEditor)
+                if (mEditorCore && mEditorCore->mCurrentEditor)
                 {
 // [SL:KB] - Patch: UI-ScriptGoToLine | Checked: 2013-12-31 (Catznip-3.6)
-			mEditorCore->mEditor->scrollTo(row, column);
+			mEditorCore->mCurrentEditor->scrollTo(row, column);
 // [/SL:KB]
-//			mEditorCore->mEditor->setCursor(row, column);
+//			mEditorCore->mCurrentEditor->setCursor(row, column);
 
 			S32 rownew = 0;
 			S32 columnnew = 0;
-			mEditorCore->mEditor->getCurrentLineAndColumn( &rownew, &columnnew, FALSE );  // don't include wordwrap
+			mEditorCore->mCurrentEditor->getCurrentLineAndColumn( &rownew, &columnnew, FALSE );  // don't include wordwrap
 			if (rownew == row && columnnew == column)
 			{
-			        mEditorCore->mEditor->deselect();
-			        mEditorCore->mEditor->setFocus(TRUE);
+			        mEditorCore->mCurrentEditor->deselect();
+			        mEditorCore->mCurrentEditor->setFocus(TRUE);
 			        sInstance->closeFloater();
 			} //else do nothing (if the cursor-position didn't change)
                 }
diff --git a/indra/newview/llfloaterscriptedprefs.cpp b/indra/newview/llfloaterscriptedprefs.cpp
index 2484a08626ab83d9fa439d509a147d557a775281..9b1baedfe13e4af2cac5f8c824d5e284600ed085 100644
--- a/indra/newview/llfloaterscriptedprefs.cpp
+++ b/indra/newview/llfloaterscriptedprefs.cpp
@@ -30,7 +30,11 @@
 
 #include "llcolorswatch.h"
 #include "llscripteditor.h"
+#include "lldirpicker.h"
+#include "llviewercontrol.h"
 
+#include "llfloaterreg.h"
+#include "llpreviewscript.h"
 
 LLFloaterScriptEdPrefs::LLFloaterScriptEdPrefs(const LLSD& key)
 :	LLFloater(key)
@@ -38,6 +42,7 @@ LLFloaterScriptEdPrefs::LLFloaterScriptEdPrefs(const LLSD& key)
 {
 	mCommitCallbackRegistrar.add("ScriptPref.applyUIColor",	boost::bind(&LLFloaterScriptEdPrefs::applyUIColor, this ,_1, _2));
 	mCommitCallbackRegistrar.add("ScriptPref.getUIColor",	boost::bind(&LLFloaterScriptEdPrefs::getUIColor, this ,_1, _2));
+	mCommitCallbackRegistrar.add("ScriptPref.SetPreprocInclude",	boost::bind(&LLFloaterScriptEdPrefs::setPreprocInclude, this));
 }
 
 BOOL LLFloaterScriptEdPrefs::postBuild()
@@ -48,6 +53,8 @@ BOOL LLFloaterScriptEdPrefs::postBuild()
 		mEditor->initKeywords();
 		mEditor->loadKeywords();
 	}
+
+	getChild<LLButton>("close_btn")->setClickedCallback(boost::bind(&LLFloaterScriptEdPrefs::closeFloater, this, false));
 	return TRUE;
 }
 
@@ -63,3 +70,18 @@ void LLFloaterScriptEdPrefs::getUIColor(LLUICtrl* ctrl, const LLSD& param)
 	LLColorSwatchCtrl* color_swatch = dynamic_cast<LLColorSwatchCtrl*>(ctrl);
 	color_swatch->setOriginal(LLUIColorTable::instance().getColor(param.asString()));
 }
+void LLFloaterScriptEdPrefs::setPreprocInclude()
+{
+	std::string proposed_name(gSavedSettings.getString("AlchemyPreProcHDDIncludeLocation"));
+	(new LLDirPickerThread(boost::bind(&LLFloaterScriptEdPrefs::changePreprocIncludePath, this, _1, _2), proposed_name))->getFile();
+}
+
+void LLFloaterScriptEdPrefs::changePreprocIncludePath(const std::vector<std::string>& filenames, const std::string& proposed_name)
+{
+	std::string dir_name = filenames[0];
+	if (!dir_name.empty() && dir_name != proposed_name)
+	{
+		std::string new_top_folder(gDirUtilp->getBaseFileName(dir_name));
+		gSavedSettings.setString("AlchemyPreProcHDDIncludeLocation", dir_name);
+	}
+}
diff --git a/indra/newview/llfloaterscriptedprefs.h b/indra/newview/llfloaterscriptedprefs.h
index ee04081335af38dfd3f137a383909ee848b9a206..fb449839ecc5a1faeec9957c6e1ffc5f21542b33 100644
--- a/indra/newview/llfloaterscriptedprefs.h
+++ b/indra/newview/llfloaterscriptedprefs.h
@@ -45,6 +45,9 @@ class LLFloaterScriptEdPrefs final : public LLFloater
 	void applyUIColor(LLUICtrl* ctrl, const LLSD& param);
 	void getUIColor(LLUICtrl* ctrl, const LLSD& param);
 	
+	void setPreprocInclude();
+	void changePreprocIncludePath(const std::vector<std::string>& filenames, const std::string& proposed_name);
+
 	LLScriptEditor* mEditor;
 };
 
diff --git a/indra/newview/llfloatersearchreplace.cpp b/indra/newview/llfloatersearchreplace.cpp
index b0d014a1f6c2c139c73ee99ca9188673e15d2bb8..0d7bab126657ac3f9ec0439b29ca63045d71b1f5 100644
--- a/indra/newview/llfloatersearchreplace.cpp
+++ b/indra/newview/llfloatersearchreplace.cpp
@@ -136,11 +136,11 @@ BOOL LLFloaterSearchReplace::handleKeyHere(KEY key, MASK mask)
 }
 
 //static 
-void LLFloaterSearchReplace::show(LLTextEditor* pEditor)
+LLFloaterSearchReplace* LLFloaterSearchReplace::show(LLTextEditor* pEditor)
 {
 	LLFloaterSearchReplace* pSelf = LLFloaterReg::getTypedInstance<LLFloaterSearchReplace>("search_replace");
 	if ( (!pSelf) || (!pEditor) )
-		return;
+		return NULL;
 
 	LLFloater *pDependeeNew = NULL, *pDependeeOld = pSelf->getDependee();
 	LLView* pView = pEditor->getParent();
@@ -170,6 +170,14 @@ void LLFloaterSearchReplace::show(LLTextEditor* pEditor)
 
 	pSelf->m_EditorHandle = pEditor->getHandle();
 	pSelf->openFloater();
+
+	return pSelf;
+}
+
+//static
+LLFloaterSearchReplace* LLFloaterSearchReplace::findInstance()
+{
+	return LLFloaterReg::findTypedInstance<LLFloaterSearchReplace>("search_replace");
 }
 
 LLTextEditor* LLFloaterSearchReplace::getEditor() const
@@ -213,4 +221,10 @@ void LLFloaterSearchReplace::onReplaceAllClick()
 	}
 }
 
+void LLFloaterSearchReplace::setCanReplace(bool can_replace)
+{
+	m_pReplaceEditor->setEnabled(can_replace);
+	getChild<LLButton>("replace_btn")->setEnabled(can_replace);
+	getChild<LLButton>("replace_all_btn")->setEnabled(can_replace);
+}
 // ============================================================================
diff --git a/indra/newview/llfloatersearchreplace.h b/indra/newview/llfloatersearchreplace.h
index 4a53047b26522aa4d238413352829cebdb5337d1..2f887a5d56447023671f9d97efa1ea9fd941d32f 100644
--- a/indra/newview/llfloatersearchreplace.h
+++ b/indra/newview/llfloatersearchreplace.h
@@ -46,14 +46,17 @@ class LLFloaterSearchReplace : public LLFloater
 	/*virtual*/ BOOL postBuild();
 	/*virtual*/ void onOpen(const LLSD& sdKey);
 	/*virtual*/ void onClose(bool fQuiting);
+	void			 setCanReplace(bool can_replace);
 
 	/*
 	 * Member functions
 	 */
 public:
-	static void   show(LLTextEditor* pEditor);
-protected:
+	static LLFloaterSearchReplace* show(LLTextEditor* pEditor);
+	static LLFloaterSearchReplace* findInstance();
 	LLTextEditor* getEditor() const;
+
+protected:
 	void          refreshHighlight();
 	void          onSearchClick();
 	void          onSearchKeystroke();
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index 37d94ef3503b677b9df1ac3f55a5614da7fe1c2e..6010fade6050ccc9843d6088ff98ec1f0c33e707 100644
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -94,6 +94,10 @@
 #include "rlvhandler.h"
 #include "rlvlocks.h"
 // [/RLVa:KB]
+// NaCl - LSL Preprocessor
+#include "fslslpreproc.h"
+#include "fslslpreprocviewer.h"
+// NaCl End
 
 const std::string HELLO_LSL =
 	"default\n"
@@ -346,7 +350,7 @@ LLScriptEdCore::LLScriptEdCore(
 	const std::string& sample,
 	const LLHandle<LLFloater>& floater_handle,
 	void (*load_callback)(void*),
-	void (*save_callback)(void*, BOOL),
+	void (*save_callback)(void*, BOOL, bool),
 //	void (*search_replace_callback) (void* userdata),
 	void* userdata,
 	bool live,
@@ -367,8 +371,12 @@ LLScriptEdCore::LLScriptEdCore(
 	mLiveHelpHistorySize(0),
 	mEnableSave(FALSE),
 	mLiveFile(NULL),
+	mLSLPreprocEnabled(LLCachedControl<bool>(gSavedSettings,"AlchemyLSLPreprocessor", FALSE)),
 	mLive(live),
 	mContainer(container),
+	mPostEditor(NULL),
+	mCurrentEditor(NULL),
+	mPreprocTab(NULL),
 	mHasScriptData(FALSE),
 	mScriptRemoved(FALSE),
 	mSaveDialogShown(FALSE)
@@ -376,7 +384,15 @@ LLScriptEdCore::LLScriptEdCore(
 	setFollowsAll();
 	setBorderVisible(FALSE);
 
-	setXMLFilename("panel_script_ed.xml");
+	if (gSavedSettings.getBOOL("AlchemyLSLPreprocessor"))
+	{
+		setXMLFilename("panel_script_ed_preproc.xml");
+		mLSLProc = std::make_unique<FSLSLPreprocessor>(this);
+	}
+	else
+	{
+		setXMLFilename("panel_script_ed.xml");
+	}
 	llassert_always(mContainer != NULL);
 }
 
@@ -397,6 +413,10 @@ LLScriptEdCore::~LLScriptEdCore()
 	{
 		mSyntaxIDConnection.disconnect();
 	}
+	if (mTogglePreprocConnection.connected())
+	{
+		mTogglePreprocConnection.disconnect();
+	}
 }
 
 void LLLiveLSLEditor::experienceChanged()
@@ -450,6 +470,7 @@ void LLLiveLSLEditor::onToggleExperience( LLUICtrl *ui, void* userdata )
 
 BOOL LLScriptEdCore::postBuild()
 {
+	mLineCol=getChild<LLTextBox>("line_col");
 // [SL:KB] - Patch: Build-ScriptEditor | Checked: 2014-01-29 (Catznip-3.6)
 	mMenuBar = getChild<LLMenuBarGL>("script_menu");
 // [/SL:KB]
@@ -462,8 +483,24 @@ BOOL LLScriptEdCore::postBuild()
 
 	mEditor = getChild<LLScriptEditor>("Script Editor");
 
+	mCurrentEditor = mEditor;
+	if (mLSLPreprocEnabled)
+	{
+		mPostEditor = getChild<FSLSLPreProcViewer>("Post Editor");
+		mPostEditor->setFollowsAll();
+		mPostEditor->setEnabled(TRUE);
+
+		mPreprocTab = getChild<LLTabContainer>("Tabset");
+		mPreprocTab->setCommitCallback(boost::bind(&LLScriptEdCore::onPreprocTabChanged, this, _2));
+	}
+
+	mTogglePreprocConnection = gSavedSettings.getControl("AlchemyLSLPreprocessor")->getSignal()->connect([&](LLControlVariable* control, const LLSD&, const LLSD&){
+		mErrorList->setCommentText(LLTrans::getString("preproc_toggle_warning"));
+		mErrorList->deleteAllItems(); // Make it visible
+	});
+
 	childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this);
-	childSetAction("Save_btn", boost::bind(&LLScriptEdCore::doSave,this,FALSE));
+	childSetAction("Save_btn", boost::bind(&LLScriptEdCore::doSave,this,FALSE, true));
 	childSetAction("Edit_btn", boost::bind(&LLScriptEdCore::openInExternalEditor, this));
 
 	initMenu();
@@ -480,6 +517,7 @@ BOOL LLScriptEdCore::postBuild()
 void LLScriptEdCore::processKeywords()
 {
 	LL_DEBUGS("SyntaxLSL") << "Processing keywords" << LL_ENDL;
+	mFunctions->clearRows();
 	mEditor->clearSegments();
 	mEditor->initKeywords();
 	mEditor->loadKeywords();
@@ -510,6 +548,13 @@ void LLScriptEdCore::processKeywords()
 	{
 		mFunctions->add(*iter);
 	}
+
+	if (mLSLPreprocEnabled && mPostEditor)
+	{
+		mPostEditor->clearSegments();
+		mPostEditor->initKeywords();
+		mPostEditor->loadKeywords();
+	}
 }
 
 void LLScriptEdCore::initMenu()
@@ -518,50 +563,52 @@ void LLScriptEdCore::initMenu()
 	LLMenuItemCallGL* menuItem;
 	
 	menuItem = getChild<LLMenuItemCallGL>("Save");
-	menuItem->setClickCallback(boost::bind(&LLScriptEdCore::doSave, this, FALSE));
+	menuItem->setClickCallback(boost::bind(&LLScriptEdCore::doSave, this, FALSE, true));
 	menuItem->setEnableCallback(boost::bind(&LLScriptEdCore::hasChanged, this));
 	
 	menuItem = getChild<LLMenuItemCallGL>("Revert All Changes");
-	menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnUndoChanges, this));
-	menuItem->setEnableCallback(boost::bind(&LLScriptEdCore::hasChanged, this));
+	menuItem->setClickCallback([&](LLUICtrl*, const LLSD&){ onBtnUndoChanges(); });
+	menuItem->setEnableCallback([&](LLUICtrl*, const LLSD&){ return (mCurrentEditor == mEditor && hasChanged()); });
 
 	menuItem = getChild<LLMenuItemCallGL>("Undo");
-	menuItem->setClickCallback(boost::bind(&LLTextEditor::undo, mEditor));
-	menuItem->setEnableCallback(boost::bind(&LLTextEditor::canUndo, mEditor));
+	menuItem->setClickCallback([&](LLUICtrl*, const LLSD&){ mCurrentEditor->undo(); });
+	menuItem->setEnableCallback([&](LLUICtrl*, const LLSD&){ return mCurrentEditor->canUndo(); });
 
 	menuItem = getChild<LLMenuItemCallGL>("Redo");
-	menuItem->setClickCallback(boost::bind(&LLTextEditor::redo, mEditor));
-	menuItem->setEnableCallback(boost::bind(&LLTextEditor::canRedo, mEditor));
+	menuItem->setClickCallback([&](LLUICtrl*, const LLSD&){ mCurrentEditor->redo(); });
+	menuItem->setEnableCallback([&](LLUICtrl*, const LLSD&){ return mCurrentEditor->canRedo(); });
 
 	menuItem = getChild<LLMenuItemCallGL>("Cut");
-	menuItem->setClickCallback(boost::bind(&LLTextEditor::cut, mEditor));
-	menuItem->setEnableCallback(boost::bind(&LLTextEditor::canCut, mEditor));
+	menuItem->setClickCallback([&](LLUICtrl*, const LLSD&){ mCurrentEditor->cut(); });
+	menuItem->setEnableCallback([&](LLUICtrl*, const LLSD&){ return mCurrentEditor->canCut(); });
 
 	menuItem = getChild<LLMenuItemCallGL>("Copy");
-	menuItem->setClickCallback(boost::bind(&LLTextEditor::copy, mEditor));
-	menuItem->setEnableCallback(boost::bind(&LLTextEditor::canCopy, mEditor));
+	menuItem->setClickCallback([&](LLUICtrl*, const LLSD&){ mCurrentEditor->copy(); });
+	menuItem->setEnableCallback([&](LLUICtrl*, const LLSD&){ return mCurrentEditor->canCopy(); });
 
 	menuItem = getChild<LLMenuItemCallGL>("Paste");
-	menuItem->setClickCallback(boost::bind(&LLTextEditor::paste, mEditor));
-	menuItem->setEnableCallback(boost::bind(&LLTextEditor::canPaste, mEditor));
+	menuItem->setClickCallback([&](LLUICtrl*, const LLSD&){ mCurrentEditor->paste(); });
+	menuItem->setEnableCallback([&](LLUICtrl*, const LLSD&){ return mCurrentEditor->canPaste(); });
 
 // [SL:KB] - Patch: Build-ScriptEditor | Checked: 2014-01-29 (Catznip-3.6)
 	menuItem = getChild<LLMenuItemCallGL>("Delete");
-	menuItem->setClickCallback(boost::bind(&LLTextEditor::doDelete, mEditor));
-	menuItem->setEnableCallback(boost::bind(&LLTextEditor::canDoDelete, mEditor));
+	menuItem->setClickCallback([&](LLUICtrl*, const LLSD&){ mCurrentEditor->doDelete(); });
+	menuItem->setEnableCallback([&](LLUICtrl*, const LLSD&){ return mCurrentEditor->canUndo(); });
 // [/SL:KB]
 
 	menuItem = getChild<LLMenuItemCallGL>("Select All");
-	menuItem->setClickCallback(boost::bind(&LLTextEditor::selectAll, mEditor));
-	menuItem->setEnableCallback(boost::bind(&LLTextEditor::canSelectAll, mEditor));
+	menuItem->setClickCallback([&](LLUICtrl*, const LLSD&){ mCurrentEditor->selectAll(); });
+	menuItem->setEnableCallback([&](LLUICtrl*, const LLSD&){ return mCurrentEditor->canSelectAll(); });
 
 	menuItem = getChild<LLMenuItemCallGL>("Deselect");
-	menuItem->setClickCallback(boost::bind(&LLTextEditor::deselect, mEditor));
-	menuItem->setEnableCallback(boost::bind(&LLTextEditor::canDeselect, mEditor));
+	menuItem->setClickCallback([&](LLUICtrl*, const LLSD&){ mCurrentEditor->deselect(); });
+	menuItem->setEnableCallback([&](LLUICtrl*, const LLSD&){ return mCurrentEditor->canDeselect(); });
 
 	menuItem = getChild<LLMenuItemCallGL>("Search / Replace...");
 // [SL:KB] - Patch: UI-FloaterSearchReplace | Checked: 2010-10-26 (Catznip-2.3)
-	menuItem->setClickCallback(boost::bind(&LLFloaterSearchReplace::show, mEditor));
+	menuItem->setClickCallback([&](LLUICtrl*, const LLSD&){ 
+		LLFloaterSearchReplace* floater = LLFloaterSearchReplace::show(mCurrentEditor);
+		floater->setCanReplace(mCurrentEditor == mEditor); });
 // [/SL:KB]
 //	menuItem->setClickCallback(boost::bind(&LLFloaterScriptSearch::show, this));
 
@@ -580,15 +627,57 @@ void LLScriptEdCore::initMenu()
 	menuItem->setEnableCallback(boost::bind(&LLScriptEdCore::enableSaveToFileMenu, this));
 }
 
+
+// NaCl - LSL Preprocessor
+void LLScriptEdCore::onPreprocTabChanged(const std::string& tab_name)
+{
+	mCurrentEditor = (tab_name == "Preprocessed" ? mPostEditor : mEditor);
+	LLFloaterSearchReplace* search_floater = LLFloaterSearchReplace::findInstance();
+	if (search_floater && (search_floater->getEditor() == mEditor || search_floater->getEditor() == mPostEditor))
+	{
+		search_floater->setCanReplace(mCurrentEditor == mEditor);
+	}
+	childSetEnabled("Insert...", mCurrentEditor == mEditor);
+}
+// NaCl End
+
 void LLScriptEdCore::setScriptText(const std::string& text, BOOL is_valid)
 {
 	if (mEditor)
 	{
-		mEditor->setText(text);
+		// NaCl - LSL Preprocessor
+		std::string ntext = text;
+		if (mLSLPreprocEnabled && mLSLProc)
+		{
+			if (mPostEditor)
+			{
+				mPostEditor->setText(ntext);
+			}
+			ntext = mLSLProc->decode(ntext);
+		}
+		LLStringUtil::replaceTabsWithSpaces(ntext, mEditor->spacesPerTab());
+		// NaCl End
+		mEditor->setText(ntext);
 		mHasScriptData = is_valid;
 	}
 }
 
+// NaCl - LSL Preprocessor
+std::string LLScriptEdCore::getScriptText()
+{
+	if (mLSLPreprocEnabled && mPostEditor)
+	{
+		//return mPostEditor->getText();
+		return mPostScript;
+	}
+	else if (mEditor)
+	{
+		return mEditor->getText();
+	}
+	return std::string();
+}
+// NaCl End
+
 void LLScriptEdCore::makeEditorPristine()
 {
 	if (mEditor)
@@ -637,23 +726,10 @@ bool LLScriptEdCore::loadScriptText(const std::string& filename)
 //	return true;
 }
 
-bool LLScriptEdCore::writeToFile(const std::string& filename)
+bool LLScriptEdCore::writeToFile(const std::string& filename, bool unprocessed)
 {
 // [SL:KB] - Patch: Build-AssetRecovery | Checked: 2013-07-28 (Catznip-3.6)
-	if (!mEditor->writeToFile(filename))
-	{
-		LL_WARNS() << "Unable to write to " << filename << LL_ENDL;
-
-		LLSD row;
-		row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?";
-		row["columns"][0]["font"] = "SANSSERIF_SMALL";
-		mErrorList->addElement(row);
-		return false;
-	}
-	return true;
-// [/SL:KB]
-//	LLFILE* fp = LLFile::fopen(filename, "wb");
-//	if (!fp)
+//	if (!mEditor->writeToFile(filename))
 //	{
 //		LL_WARNS() << "Unable to write to " << filename << LL_ENDL;
 //
@@ -663,18 +739,37 @@ bool LLScriptEdCore::writeToFile(const std::string& filename)
 //		mErrorList->addElement(row);
 //		return false;
 //	}
-//
-//	std::string utf8text = mEditor->getText();
-//
-//	// Special case for a completely empty script - stuff in one space so it can store properly.  See SL-46889
-//	if (utf8text.size() == 0)
-//	{
-//		utf8text = " ";
-//	}
-//
-//	fputs(utf8text.c_str(), fp);
-//	fclose(fp);
 //	return true;
+// [/SL:KB]
+	LLFILE* fp = LLFile::fopen(filename, "wb");
+	if (!fp)
+	{
+		LL_WARNS() << "Unable to write to " << filename << LL_ENDL;
+
+		LLSD row;
+		row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?";
+		row["columns"][0]["font"] = "SANSSERIF_SMALL";
+		mErrorList->addElement(row);
+		return false;
+	}
+
+	// NaCl - LSL Preprocessor
+	std::string utf8text;
+	if(!unprocessed)
+		utf8text = getScriptText();
+	else
+		utf8text = mEditor->getText();
+	// NaCl End
+
+	// Special case for a completely empty script - stuff in one space so it can store properly.  See SL-46889
+	if (utf8text.size() == 0)
+	{
+		utf8text = " ";
+	}
+
+	fputs(utf8text.c_str(), fp);
+	fclose(fp);
+	return true;
 }
 
 void LLScriptEdCore::sync()
@@ -687,7 +782,7 @@ void LLScriptEdCore::sync()
         if (LLFile::stat(tmp_file, &s) == 0) // file exists
         {
             mLiveFile->ignoreNextUpdate();
-            writeToFile(tmp_file);
+            writeToFile(tmp_file, mLSLPreprocEnabled);
         }
     }
 }
@@ -714,11 +809,23 @@ void LLScriptEdCore::draw()
 		args["[LINE]"] = llformat ("%d", line);
 		args["[COLUMN]"] = llformat ("%d", column);
 		cursor_pos = LLTrans::getString("CursorPos", args);
-		getChild<LLUICtrl>("line_col")->setValue(cursor_pos);
+		mLineCol->setValue(cursor_pos);
+	}
+	else if (mPostEditor && mPostEditor->hasFocus())
+	{
+		S32 line = 0;
+		S32 column = 0;
+		mPostEditor->getCurrentLineAndColumn( &line, &column, FALSE );  // don't include wordwrap
+		LLStringUtil::format_map_t args;
+		std::string cursor_pos;
+		args["[LINE]"] = llformat ("%d", line);
+		args["[COLUMN]"] = llformat ("%d", column);
+		cursor_pos = LLTrans::getString("CursorPos", args);
+		mLineCol->setValue(cursor_pos);
 	}
 	else
 	{
-		getChild<LLUICtrl>("line_col")->setValue(LLStringUtil::null);
+		mLineCol->setValue(LLStringUtil::null);
 	}
 
 	updateDynamicHelp();
@@ -1059,44 +1166,37 @@ void LLScriptEdCore::onBtnInsertFunction(LLUICtrl *ui, void* userdata)
 	self->setHelpPage(self->mFunctions->getSimple());
 }
 
-void LLScriptEdCore::doSave( BOOL close_after_save )
+void LLScriptEdCore::doSave(BOOL close_after_save, bool sync /*= true*/)
+{
+	mErrorList->deleteAllItems();
+	mErrorList->setCommentText(std::string());
+
+	if (mLSLPreprocEnabled && mLSLProc)
+	{
+		LL_INFOS() << "passing to preproc" << LL_ENDL;
+		mLSLProc->preprocess_script(close_after_save, sync);
+	}
+	else
+	{
+		if( mSaveCallback )
+		{
+			mSaveCallback( mUserdata, close_after_save, sync );
+		}
+	}
+}
+
+void LLScriptEdCore::doSaveComplete( void* userdata, BOOL close_after_save, bool sync)
 {
 	add(LLStatViewer::LSL_SAVES, 1);
 
 	if( mSaveCallback )
 	{
-		mSaveCallback( mUserdata, close_after_save );
+		mSaveCallback( mUserdata, close_after_save, sync );
 	}
 }
 
 void LLScriptEdCore::openInExternalEditor()
 {
-	delete mLiveFile; // deletes file
-
-	// Generate a suitable filename
-    std::string script_name = mScriptName;
-    std::string forbidden_chars = "<>:\"\\/|?*";
-    for (std::string::iterator c = forbidden_chars.begin(); c != forbidden_chars.end(); c++)
-    {
-        script_name.erase(std::remove(script_name.begin(), script_name.end(), *c), script_name.end());
-    }
-	std::string filename = mContainer->getTmpFileName(script_name);
-
-    // Save the script to a temporary file.
-    if (!writeToFile(filename))
-    {
-        // In case some characters from script name are forbidden
-        // and not accounted for, name is too long or some other issue,
-        // try file that doesn't include script name
-        script_name.clear();
-        filename = mContainer->getTmpFileName(script_name);
-        writeToFile(filename);
-    }
-
-	// Start watching file changes.
-	mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLScriptEdContainer::onExternalChange, mContainer, _1));
-	mLiveFile->addToEventTimer();
-
 	// Open it in external editor.
 	{
 		LLExternalEditor ed;
@@ -1119,6 +1219,35 @@ void LLScriptEdCore::openInExternalEditor()
 			return;
 		}
 
+		// Script contents clobbered when Edit button
+		// clicked with preprocessor active. Fix from NaCl (code moved
+		// from above).
+		delete mLiveFile; // deletes file
+
+		// Generate a suitable filename
+		std::string script_name = mScriptName;
+		std::string forbidden_chars = "<>:\"\\/|?*";
+		for (std::string::iterator c = forbidden_chars.begin(); c != forbidden_chars.end(); c++)
+		{
+			script_name.erase(std::remove(script_name.begin(), script_name.end(), *c), script_name.end());
+		}
+		std::string filename = mContainer->getTmpFileName(script_name);
+
+		// Save the script to a temporary file.
+		if (!writeToFile(filename, mLSLPreprocEnabled))
+		{
+			// In case some characters from script name are forbidden
+			// and not accounted for, name is too long or some other issue,
+			// try file that doesn't include script name
+			script_name.clear();
+			filename = mContainer->getTmpFileName(script_name);
+			writeToFile(filename, mLSLPreprocEnabled);
+		}
+
+		// Start watching file changes.
+		mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLScriptEdContainer::onExternalChange, mContainer, _1));
+		mLiveFile->addToEventTimer();
+
 		status = ed.run(filename);
 		if (status != LLExternalEditor::EC_SUCCESS)
 		{
@@ -1154,11 +1283,24 @@ void LLScriptEdCore::onErrorList(LLUICtrl*, void* user_data)
 		sscanf(line.c_str(), "%d %d", &row, &column);
 		//LL_INFOS() << "LLScriptEdCore::onErrorList() - " << row << ", "
 		//<< column << LL_ENDL;
+		if (gSavedSettings.getBOOL("AlchemyLSLPreprocessor") && self->mPostEditor && self->mPreprocTab)
+		{
+			self->mPreprocTab->selectTabByName("Preprocessed");
+			self->getChild<LLPanel>("Preprocessed")->setFocus(TRUE);
+			self->mPostEditor->setFocus(TRUE);
+// [SL:KB] - Patch: UI-ScriptGoToLine | Checked: 2013-12-31 (Catznip-3.6)
+			self->mPostEditor->scrollTo(row, column);
+// [/SL:KB]
+//			self->mPostEditor->setCursor(row, column);
+		}
+		else
+		{
 // [SL:KB] - Patch: UI-ScriptGoToLine | Checked: 2013-12-31 (Catznip-3.6)
-		self->mEditor->scrollTo(row, column);
+			self->mEditor->scrollTo(row, column);
 // [/SL:KB]
-//		self->mEditor->setCursor(row, column);
-		self->mEditor->setFocus(TRUE);
+//			self->mEditor->setCursor(row, column);
+			self->mEditor->setFocus(TRUE);
+		}
 	}
 }
 
@@ -1217,6 +1359,27 @@ void LLScriptEdCore::deleteBridges()
 // virtual
 BOOL LLScriptEdCore::handleKeyHere(KEY key, MASK mask)
 {
+	bool just_control = MASK_CONTROL == (mask & MASK_MODIFIERS);
+
+	if(('S' == key) && just_control)
+	{
+		if(mSaveCallback)
+		{
+			// don't close after saving
+			// NaCl - LSL Preprocessor
+			if (!hasChanged())
+			{
+				LL_INFOS("Scriptsave") << "Save Not Needed" << LL_ENDL;
+				return TRUE;
+			}
+			doSave(FALSE);
+			// NaCl End
+				
+			//mSaveCallback(mUserdata, FALSE);
+		}
+
+		return TRUE;
+	}
 // [SL:KB] - Patch: Build-ScriptEditor | Checked: 2014-01-29 (Catznip-3.6)
 	if (mMenuBar->handleAcceleratorKey(key, mask))
 	{
@@ -1302,12 +1465,12 @@ void LLScriptEdCore::saveScriptToFile(const std::vector<std::string>& filenames,
 	LLScriptEdCore* self = (LLScriptEdCore*)data;
 	if (self)
 	{
-		std::string filename = filenames[0];
-		std::string scriptText = self->mEditor->getText();
+		const std::string& filename = filenames[0];
+		const std::string& scriptText = self->mEditor->getText();
 		llofstream fout(filename.c_str());
 		fout << (scriptText);
 		fout.close();
-		self->mSaveCallback(self->mUserdata, FALSE);
+		self->mSaveCallback(self->mUserdata, FALSE, true);
 	}
 }
 
@@ -1498,7 +1661,7 @@ void LLScriptEdContainer::onBackupTimer()
 	{
 		if (mBackupFilename.empty())
 			mBackupFilename = getBackupFileName();
-		mScriptEd->writeToFile(mBackupFilename);
+		mScriptEd->writeToFile(mBackupFilename, true);
 	}
 }
 // [/SL:KB]
@@ -1533,7 +1696,13 @@ bool LLScriptEdContainer::onExternalChange(const std::string& filename)
 	}
 
 	// Disable sync to avoid recursive load->save->load calls.
-	saveIfNeeded(false);
+	// LSL preprocessor
+	//  Don't call saveIfNeeded directly, as we might have to run the
+	// preprocessor first. saveIfNeeded will be invoked via callback. Make sure
+	// to pass sync = false - we don't need to update the external editor in this
+	// case or the next save will be ignored!
+	//saveIfNeeded(false);
+	mScriptEd->doSave(FALSE, false);
 	return true;
 }
 
@@ -1611,8 +1780,8 @@ void LLPreviewLSL::draw()
 void LLPreviewLSL::callbackLSLCompileSucceeded()
 {
 	LL_INFOS() << "LSL Bytecode saved" << LL_ENDL;
-	mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessful"));
-	mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete"));
+	mScriptEd->mErrorList->addCommentText(LLTrans::getString("CompileSuccessful"));
+	mScriptEd->mErrorList->addCommentText(LLTrans::getString("SaveComplete"));
 
 // [SL:KB] - Patch: Build-ScriptRecover | Checked: 2011-11-23 (Catznip-3.2)
 	// Script was successfully saved so delete our backup copy if we have one and the editor is still pristine
@@ -1743,11 +1912,11 @@ void LLPreviewLSL::onLoad(void* userdata)
 }
 
 // static
-void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save)
+void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save, bool sync)
 {
 	LLPreviewLSL* self = (LLPreviewLSL*)userdata;
 	self->mCloseAfterSave = close_after_save;
-	self->saveIfNeeded();
+	self->saveIfNeeded(sync);
 }
 
 /*static*/
@@ -1783,7 +1952,6 @@ void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/)
     }
 
     mPendingUploads = 0;
-    mScriptEd->mErrorList->deleteAllItems();
     mScriptEd->mEditor->makePristine();
 
     if (sync)
@@ -1795,21 +1963,45 @@ void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/)
     const LLInventoryItem *inv_item = getItem();
     // save it out to asset server
     std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent");
+
+	// NaCL - LSL Preprocessor
+	mScriptEd->enableSave(FALSE); // Clear the enable save flag (FIRE-10173)
+	bool inventory_mono = gSavedSettings.getBOOL("AlchemyInventoryScriptsMono");
+	if (gSavedSettings.getBOOL("AlchemyLSLPreprocessor"))
+	{
+		bool mono_directive = FSLSLPreprocessor::mono_directive(mScriptEd->getScriptText(), inventory_mono);
+		if (mono_directive != inventory_mono)
+		{
+			std::string message;
+			if (mono_directive)
+			{
+				message = LLTrans::getString("fs_preprocessor_mono_directive_override");
+			}
+			else
+			{
+				message = LLTrans::getString("fs_preprocessor_lsl2_directive_override");
+			}
+			inventory_mono = mono_directive;
+			mScriptEd->mErrorList->addCommentText(message);
+		}
+	}
+	// NaCl End
+
     if(inv_item)
     {
         getWindow()->incBusyCount();
         mPendingUploads++;
         if (!url.empty())
         {
-            std::string buffer(mScriptEd->mEditor->getText());
+            std::string buffer(mScriptEd->getScriptText());
 
             LLUUID old_asset_id = inv_item->getAssetUUID().isNull() ? mScriptEd->getAssetID() : inv_item->getAssetUUID();
-
             LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLScriptAssetUpload>(mItemUUID, buffer, 
                 [old_asset_id](LLUUID itemId, LLUUID, LLUUID, LLSD response) {
                     LLFileSystem::removeFile(old_asset_id, LLAssetType::AT_LSL_TEXT);
                     LLPreviewLSL::finishedLSLUpload(itemId, response);
-                }));
+                },
+                inventory_mono ? LLScriptAssetUpload::MONO : LLScriptAssetUpload::LSL2));
 
             LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
         }
@@ -1980,10 +2172,8 @@ void LLLiveLSLEditor::callbackLSLCompileSucceeded(const LLUUID& task_id,
 												  bool is_script_running)
 {
 	LL_DEBUGS() << "LSL Bytecode saved" << LL_ENDL;
-	mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessful"));
-	mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete"));
-	getChild<LLCheckBoxCtrl>("running")->set(is_script_running);
-	mIsSaving = FALSE;
+	mScriptEd->mErrorList->addCommentText(LLTrans::getString("CompileSuccessful"));
+	mScriptEd->mErrorList->addCommentText(LLTrans::getString("SaveComplete"));
 
 // [SL:KB] - Patch: Build-ScriptRecover | Checked: 2011-11-23 (Catznip-3.2)
 	// Script was successfully saved so delete our backup copy if we have one and the editor is still pristine
@@ -1993,6 +2183,8 @@ void LLLiveLSLEditor::callbackLSLCompileSucceeded(const LLUUID& task_id,
 	}
 // [/SL:KB]
 
+	getChild<LLCheckBoxCtrl>("running")->set(is_script_running);
+	mIsSaving = FALSE;
 	closeIfNeeded();
 }
 
@@ -2023,6 +2215,7 @@ void LLLiveLSLEditor::callbackLSLCompileFailed(const LLSD& compile_errors)
 	}
 // [/SL:KB]
 
+	mIsSaving = FALSE;
 	closeIfNeeded();
 }
 
@@ -2151,6 +2344,14 @@ void LLLiveLSLEditor::onLoadComplete(const LLUUID& asset_id,
 	{
 		if( LL_ERR_NOERR == status )
 		{
+			if( !instance->getItem() )
+			{
+				LL_WARNS() << "getItem() returns 0, item went away while loading script()" << LL_ENDL;
+				instance->mAssetStatus = PREVIEW_ASSET_ERROR;
+				delete floater_key;
+				return;
+			}
+
 			instance->loadScriptText(asset_id, type);
 			instance->mScriptEd->setEnableEditing(TRUE);
 			instance->mAssetStatus = PREVIEW_ASSET_LOADED;
@@ -2433,14 +2634,13 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/)
     // save the script
     mScriptEd->enableSave(FALSE);
     mScriptEd->mEditor->makePristine();
-    mScriptEd->mErrorList->deleteAllItems();
-    mScriptEd->mEditor->makePristine();
 
     if (sync)
     {
         mScriptEd->sync();
     }
     bool isRunning = getChild<LLCheckBoxCtrl>("running")->get();
+	mIsSaving = TRUE;
     getWindow()->incBusyCount();
     mPendingUploads++;
 
@@ -2448,7 +2648,7 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/)
 
     if (!url.empty())
     {
-        std::string buffer(mScriptEd->mEditor->getText());
+		std::string buffer(mScriptEd->getScriptText());
         LLUUID old_asset_id = mScriptEd->getAssetID();
 
         LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLScriptAssetUpload>(mObjectUUID, mItemUUID, 
@@ -2486,14 +2686,13 @@ void LLLiveLSLEditor::onLoad(void* userdata)
 }
 
 // static
-void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save)
+void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save, bool sync)
 {
 	LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
 	if(self)
 	{
 		self->mCloseAfterSave = close_after_save;
-		self->mScriptEd->mErrorList->setCommentText("");
-		self->saveIfNeeded();
+		self->saveIfNeeded(sync);
 	}
 }
 
diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h
index 20dbb1c0b515421941f6e976a47653fb17bb1ce6..e9757a45e9da997a724b813a9a69bd343d8dc3af 100644
--- a/indra/newview/llpreviewscript.h
+++ b/indra/newview/llpreviewscript.h
@@ -52,6 +52,8 @@ class LLViewerInventoryItem;
 class LLScriptEdContainer;
 class LLFloaterGotoLine;
 class LLFloaterExperienceProfile;
+class FSLSLPreprocessor;
+class FSLSLPreProcViewer;
 
 class LLLiveLSLFile final : public LLLiveFile
 {
@@ -79,6 +81,9 @@ class LLScriptEdCore final : public LLPanel
 //	friend class LLFloaterScriptSearch;
 	friend class LLScriptEdContainer;
 	friend class LLFloaterGotoLine;
+	// NaCl - LSL Preprocessor
+	friend class FSLSLPreprocessor;
+	// NaCl End
 
 protected:
 	// Supposed to be invoked only by the container.
@@ -87,7 +92,7 @@ class LLScriptEdCore final : public LLPanel
 		const std::string& sample,
 		const LLHandle<LLFloater>& floater_handle,
 		void (*load_callback)(void* userdata),
-		void (*save_callback)(void* userdata, BOOL close_after_save),
+		void (*save_callback)(void* userdata, BOOL close_after_save, bool sync),
 //		void (*search_replace_callback)(void* userdata),
 		void* userdata,
 		bool live,
@@ -107,12 +112,16 @@ class LLScriptEdCore final : public LLPanel
 	bool			canLoadOrSaveToFile( void* userdata );
 
 	void            setScriptText(const std::string& text, BOOL is_valid);
+	// NaCL - LSL Preprocessor
+	std::string		getScriptText();
+	void			doSaveComplete(void* userdata, BOOL close_after_save, bool sync);
+	// NaCl End
 	void			makeEditorPristine();
 	bool			loadScriptText(const std::string& filename);
-	bool			writeToFile(const std::string& filename);
+	bool			writeToFile(const std::string& filename, bool unprocessed);
 	void			sync();
 	
-	void			doSave( BOOL close_after_save );
+	void			doSave(BOOL close_after_save, bool sync = true);
 
 	bool			handleSaveChangesDialog(const LLSD& notification, const LLSD& response);
 	bool			handleReloadFromServerDialog(const LLSD& notification, const LLSD& response);
@@ -146,6 +155,11 @@ class LLScriptEdCore final : public LLPanel
     LLUUID 			getAssetID() { return mAssetID; }
 
 private:
+	// NaCl - LSL Preprocessor
+	LLCachedControl<bool> mLSLPreprocEnabled; 
+	boost::signals2::connection	mTogglePreprocConnection;
+	void		onPreprocTabChanged(const std::string& tab_name);
+	// NaCl End
 	void		onBtnDynamicHelp();
 	void		onBtnUndoChanges();
 
@@ -175,7 +189,7 @@ class LLScriptEdCore final : public LLPanel
 // [/SL:KB]
 	LLScriptEditor*	mEditor;
 	void			(*mLoadCallback)(void* userdata);
-	void			(*mSaveCallback)(void* userdata, BOOL close_after_save);
+	void			(*mSaveCallback)(void* userdata, BOOL close_after_save, bool sync);
 //	void			(*mSearchReplaceCallback) (void* userdata);
     void*			mUserdata;
     LLComboBox		*mFunctions;
@@ -195,6 +209,15 @@ class LLScriptEdCore final : public LLPanel
 	BOOL			mSaveDialogShown;
     LLUUID          mAssetID;
 
+	LLTextBox*		mLineCol;
+	// NaCl - LSL Preprocessor
+	std::unique_ptr<FSLSLPreprocessor>	mLSLProc;
+	FSLSLPreProcViewer*	mPostEditor;
+	LLScriptEditor*		mCurrentEditor;
+	LLTabContainer*		mPreprocTab;
+	std::string			mPostScript;
+	// NaCl End
+
 	LLScriptEdContainer* mContainer; // parent view
 
 public:
@@ -246,7 +269,7 @@ class LLPreviewLSL final : public LLScriptEdContainer
 
 //	static void onSearchReplace(void* userdata);
 	static void onLoad(void* userdata);
-	static void onSave(void* userdata, BOOL close_after_save);
+	static void onSave(void* userdata, BOOL close_after_save, bool sync);
 	
 	static void onLoadComplete(const LLUUID& uuid,
 							   LLAssetType::EType type,
@@ -311,7 +334,7 @@ class LLLiveLSLEditor final : public LLScriptEdContainer
 
 //	static void onSearchReplace(void* userdata);
 	static void onLoad(void* userdata);
-	static void onSave(void* userdata, BOOL close_after_save);
+	static void onSave(void* userdata, BOOL close_after_save, bool sync);
 
 	static void onLoadComplete(const LLUUID& asset_uuid,
 							   LLAssetType::EType type,
diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp
index 288125331a3767da364924052bbead4fda626dd6..f6c11d773164a7df67d643b96b7f8ee761666fde 100644
--- a/indra/newview/llviewerassetupload.cpp
+++ b/indra/newview/llviewerassetupload.cpp
@@ -749,10 +749,10 @@ LLUUID LLBufferedAssetUploadInfo::finishUpload(LLSD &result)
 
 //=========================================================================
 
-LLScriptAssetUpload::LLScriptAssetUpload(LLUUID itemId, std::string buffer, invnUploadFinish_f finish):
+LLScriptAssetUpload::LLScriptAssetUpload(LLUUID itemId, std::string buffer, invnUploadFinish_f finish, TargetType_t targetType):
     LLBufferedAssetUploadInfo(itemId, LLAssetType::AT_LSL_TEXT, buffer, finish),
     mExerienceId(),
-    mTargetType(LSL2),
+    mTargetType(targetType),
     mIsRunning(false)
 {
 }
@@ -773,7 +773,7 @@ LLSD LLScriptAssetUpload::generatePostBody()
     if (getTaskId().isNull())
     {
         body["item_id"] = getItemId();
-        body["target"] = "lsl2";
+        body["target"] = (getTargetType() == MONO) ? "mono" : "lsl2";
     }
     else
     {
diff --git a/indra/newview/llviewerassetupload.h b/indra/newview/llviewerassetupload.h
index e027fa640bafd7a5fd91c76641d3f1eec3d759a5..1278a1d1bb163e6af24aeea7881975fde568f0bb 100644
--- a/indra/newview/llviewerassetupload.h
+++ b/indra/newview/llviewerassetupload.h
@@ -219,7 +219,7 @@ class LLScriptAssetUpload : public LLBufferedAssetUploadInfo
         MONO
     };
 
-    LLScriptAssetUpload(LLUUID itemId, std::string buffer, invnUploadFinish_f finish);
+    LLScriptAssetUpload(LLUUID itemId, std::string buffer, invnUploadFinish_f finish, TargetType_t targetType = MONO);
     LLScriptAssetUpload(LLUUID taskId, LLUUID itemId, TargetType_t targetType, 
             bool isRunning, LLUUID exerienceId, std::string buffer, taskUploadFinish_f finish);
 
diff --git a/indra/newview/skins/default/xui/en/floater_script_ed_prefs.xml b/indra/newview/skins/default/xui/en/floater_script_ed_prefs.xml
index 8e4bcb3eb0da36a7da43f7f3b704a6d2d637dab9..769a944f92d6422cffe1398957d8fd79211f88c5 100644
--- a/indra/newview/skins/default/xui/en/floater_script_ed_prefs.xml
+++ b/indra/newview/skins/default/xui/en/floater_script_ed_prefs.xml
@@ -2,7 +2,7 @@
 <floater
  legacy_header_height="18"
  can_resize="false"
- height="354"
+ height="528"
  layout="topleft"
  name="floater_script_colors"
  help_topic="script_colors"
@@ -324,13 +324,12 @@
     <script_editor
      left="8"
      right="-8"
-     top="176"
-     bottom="-8"
+     top_pad="15"
      type="string"
      length="1"
      follows="left|top|right|bottom"
      font="Monospace"
-     height="100"
+     height="165"
      ignore_tab="false"
      layout="topleft"
      max_length="300"
@@ -356,4 +355,105 @@ default
     }
 }
     </script_editor>
+
+	<text
+		follows="left|top"
+		height="15"
+		layout="topleft"
+		left="12"
+		name="prefs_label"
+		top_pad="6"
+		width="150">
+		Script Editor Options:
+    </text>
+	<check_box
+		control_name="AlchemyLSLPreprocessor"
+		follows="left|top"
+		height="16"
+		top_pad="2"
+		label="Enable LSL preprocessor"
+		tool_tip="When checked, the LSL preprocessor is enabled."
+		name="preproc_checkbox" />
+	<check_box
+		control_name="AlchemyPreProcLSLOptimizer"
+		enabled_control="AlchemyLSLPreprocessor"
+		follows="left|top"
+		height="16"
+		top_pad="2"
+		left_delta="16"
+		label="Script optimizer"
+		tool_tip="When checked, the LSL preprocessor will optimize space used by scripts."
+		name="preprocoptimizer_checkbox" />
+	<check_box
+		control_name="AlchemyPreProcLSLSwitch"
+		enabled_control="AlchemyLSLPreprocessor"
+		follows="left|top"
+		height="16"
+		top_pad="2"
+		label="switch() statement"
+		tool_tip="When checked, the LSL preprocessor will allow the use of the switch() statement for script flow control."
+		name="preprocswitch_checkbox" />
+	<check_box
+		control_name="AlchemyPreProcLSLLazyLists"
+		enabled_control="AlchemyLSLPreprocessor"
+		follows="left|top"
+		height="16"
+		top_pad="2"
+		label="Lazy lists"
+		tool_tip="When checked, the LSL preprocessor will allow the use of syntax extensions for list handling."
+		name="preproclazy_checkbox" />
+	<check_box
+		control_name="AlchemyPreProcEnableHDDInclude"
+		enabled_control="AlchemyLSLPreprocessor"
+		follows="left|top"
+		top_pad="2"
+		height="16"
+		label="#includes from local disk"
+		tool_tip="When checked, the LSL preprocessor will allow #include statements to reference files on your local disk."
+		name="preprocinclude_checkbox" />
+	<text
+		follows="left|top"
+		height="16"
+		type="string"
+		length="1"
+		layout="topleft"
+		name="lslpreprocinclude_textbox"
+		top_pad="2"
+		width="256">
+		Preprocessor include path:
+	</text>
+	<line_editor
+		control_name="AlchemyPreProcHDDIncludeLocation"
+		border_style="line"
+		border_thickness="1"
+		follows="left|top"
+		height="23"
+		enabled_control="AlchemyPreProcEnableHDDInclude"
+		max_length_chars="4096"
+		name="preprocinclude_location"
+		top_pad="0"
+		width="235" />
+	<button
+		follows="left|top"
+		height="23"
+		enabled_control="AlchemyPreProcEnableHDDInclude"
+		label="..."
+		label_selected="Browse"
+		left_pad="5"
+		name="SetPreprocInclude"
+		top_delta="0"
+		width="30">
+		<button.commit_callback
+		function="ScriptPref.SetPreprocInclude" />
+	</button>
+       
+	<button
+		follows="top|left"
+		height="23"
+		layout="topleft"
+		top_pad="6"
+		left="115"
+		name="close_btn"
+		width="100"
+		label="OK" />
 </floater>
diff --git a/indra/newview/skins/default/xui/en/language_settings.xml b/indra/newview/skins/default/xui/en/language_settings.xml
index cf3c5ccd45c861e7803b8c4e11de0b8a275055d0..4b7cb84044d5564952fd3afaebdd01d95af8bfc1 100644
--- a/indra/newview/skins/default/xui/en/language_settings.xml
+++ b/indra/newview/skins/default/xui/en/language_settings.xml
@@ -37,6 +37,7 @@
 
 	<string name="TimeHour">hour,datetime,slt</string>
 	<string name="TimeMin">min,datetime,slt</string>	
+	<string name="TimeSec">second,datetime,slt</string>
 	<string name="TimeYear">year,datetime,slt</string>	
 	<string name="TimeDay">day,datetime,slt</string>	
 	<string name="TimeMonth">mthnum,datetime,slt</string>	
diff --git a/indra/newview/skins/default/xui/en/panel_script_ed.xml b/indra/newview/skins/default/xui/en/panel_script_ed.xml
index a70ae1180f53f0b2a8431ccdb93a1256c9af7214..436834a34bc6ddbe587952ab9d92dd70bc8010a1 100644
--- a/indra/newview/skins/default/xui/en/panel_script_ed.xml
+++ b/indra/newview/skins/default/xui/en/panel_script_ed.xml
@@ -70,7 +70,7 @@
           <menu_item_separator
            layout="topleft" />
           <menu_item_call
-           label="Colors..."
+           label="Script Preferences..."
            layout="topleft"
            name="Colors">
             <menu_item_call.on_click
@@ -129,6 +129,11 @@
         layout="topleft"
         name="Select All"
         shortcut="control|A" />
+      <menu_item_call
+        enabled="false"
+        label="Deselect"
+        layout="topleft"
+        name="Deselect" />
       <menu_item_separator
         layout="topleft"
         name="separator3" />
diff --git a/indra/newview/skins/default/xui/en/panel_script_ed_preproc.xml b/indra/newview/skins/default/xui/en/panel_script_ed_preproc.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0306a4afa089a8dd713b93186d04973261d52ad0
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_script_ed_preproc.xml
@@ -0,0 +1,295 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+  bevel_style="none"
+  border_style="line"
+  follows="left|top|right|bottom"
+ height="522"
+  layout="topleft"
+  left="0"
+  name="script panel"
+  width="497">
+  <panel.string
+    name="loading">
+    Loading...
+  </panel.string>
+  <panel.string
+    name="can_not_view">
+    You can not view or edit this script, since it has been set as &quot;no copy&quot;. You need full permissions to view or edit a script inside an object.
+  </panel.string>
+  <panel.string
+    name="public_objects_can_not_run">
+    Public Objects cannot run scripts
+  </panel.string>
+  <panel.string
+    name="script_running">
+    Running
+  </panel.string>
+  <panel.string
+    name="Title">
+    Script: [NAME]
+  </panel.string>
+  <menu_bar
+    bg_visible="false"
+    follows="left|top"
+    height="18"
+    layout="topleft"
+    left="0"
+    mouse_opaque="false"
+    name="script_menu"
+    width="476">
+    <menu
+      top="0"
+      height="62"
+      label="File"
+      layout="topleft"
+      left="0"
+      mouse_opaque="false"
+      name="File"
+      width="138">
+      <menu_item_call
+        label="Save"
+        layout="topleft"
+        name="Save"
+        shortcut="control|S" />
+      <menu_item_separator
+        layout="topleft" />
+      <menu_item_call
+        label="Revert All Changes"
+        layout="topleft"
+        name="Revert All Changes" />
+      <menu_item_separator
+        layout="topleft" />
+      <menu_item_call
+        label="Load from file..."
+        layout="topleft"
+        name="LoadFromFile" />
+      <menu_item_call
+        label="Save to file..."
+        layout="topleft"
+        name="SaveToFile" />
+          <menu_item_separator
+           layout="topleft" />
+          <menu_item_call
+           label="Script Preferences..."
+           layout="topleft"
+           name="Colors">
+            <menu_item_call.on_click
+             function="Floater.Toggle"
+             parameter="script_colors"/>
+          </menu_item_call>
+    </menu>
+    <menu
+      top="0"
+      height="198"
+      label="Edit"
+      layout="topleft"
+      mouse_opaque="false"
+      name="Edit"
+      width="139">
+      <menu_item_call
+        enabled="false"
+        label="Undo"
+        layout="topleft"
+        name="Undo"
+        shortcut="control|Z" />
+      <menu_item_call
+        enabled="false"
+        label="Redo"
+        layout="topleft"
+        name="Redo"
+        shortcut="control|Y" />
+      <menu_item_separator
+        layout="topleft" />
+      <menu_item_call
+        enabled="false"
+        label="Cut"
+        layout="topleft"
+        name="Cut"
+        shortcut="control|X" />
+      <menu_item_call
+        enabled="false"
+        label="Copy"
+        layout="topleft"
+        name="Copy"
+        shortcut="control|C" />
+      <menu_item_call
+        enabled="false"
+        label="Paste"
+        layout="topleft"
+        name="Paste"
+        shortcut="control|V" />
+      <menu_item_call
+        enabled="false"
+        label="Delete"
+        layout="topleft"
+        name="Delete"
+        shortcut="Del" />
+      <menu_item_call
+        label="Select All"
+        layout="topleft"
+        name="Select All"
+        shortcut="control|A" />
+      <menu_item_call
+        enabled="false"
+        label="Deselect"
+        layout="topleft"
+        name="Deselect" />
+      <menu_item_separator
+        layout="topleft"
+        name="separator3" />
+      <menu_item_call
+        label="Search / Replace..."
+        layout="topleft"
+             name="Search / Replace..."
+             shortcut="control|F" />
+            <menu_item_call
+             label="Go to line..."
+             layout="topleft"
+             name="Go to line..."
+             shortcut="control|G" />
+    </menu>
+    <menu
+      top="0"
+      height="34"
+      label="LSL Reference"
+      layout="topleft"
+      mouse_opaque="false"
+      name="Help"
+      width="112">
+      <menu_item_call
+        label="Keyword Help..."
+        layout="topleft"
+             name="Keyword Help..."
+             shortcut="shift|F1" />
+    </menu>
+  </menu_bar>
+    <tab_container
+     follows="all"
+     halign="left"
+     height="378"
+     left="0"
+	 top_pad="2"
+     name="Tabset"
+     tab_position="bottom"
+     tab_width="100"
+     tab_padding_right="0"
+	 tab_height="16"
+     width="487">
+	<panel
+	 bevel_style="none"
+	 border_style="line"
+	 follows="left|top|right|bottom"
+	 height="377"
+	 layout="topleft"
+	 left="0"
+	 top="0"
+	 name="Script"
+	 label="Script"
+	 width="487">
+		<script_editor
+		 left="0"
+		 top="0"
+		 type="string"
+		 length="1"
+		 follows="left|top|right|bottom"
+		 font="Monospace"
+		 height="376"
+		 ignore_tab="false"
+		 layout="topleft"
+		 max_length="262144"
+		 name="Script Editor"
+		 text_color="ScriptText"
+		 default_color="ScriptText"
+		 bg_writeable_color="ScriptBackground"
+		 bg_focus_color="ScriptBackground"
+		 text_readonly_color="ScriptText"
+		 bg_readonly_color="ScriptBackground"
+		 bg_selected_color="ScriptSelectedColor"
+		 cursor_color="ScriptCursorColor"
+		 width="487"
+		 enable_tooltip_paste="true"
+		 word_wrap="true"
+		 show_context_menu="true">
+			Loading...
+		</script_editor>
+	</panel>
+	<panel
+	 bevel_style="none"
+	 border_style="line"
+	 follows="left|top|right|bottom"
+	 height="377"
+	 layout="topleft"
+	 left="0"
+	 name="Preprocessed"
+	 label="Preprocessed"
+	 width="487">
+		<lsl_preproc_viewer
+		 left="0"
+		 top="0"
+		 type="string"
+		 length="1"
+		 follows="left|top|right|bottom"
+		 font="Monospace"
+		 height="376"
+		 ignore_tab="false"
+		 layout="topleft"
+		 max_length="262144"
+		 name="Post Editor"
+		 text_color="ScriptText"
+		 default_color="ScriptText"
+		 bg_writeable_color="ScriptBackground"
+		 bg_focus_color="ScriptBackground"
+		 text_readonly_color="ScriptText"
+		 bg_readonly_color="ScriptBackground"
+		 bg_selected_color="ScriptSelectedColor"
+		 cursor_color="ScriptCursorColor"
+		 width="487"
+		 word_wrap="true"
+		 show_context_menu="true">
+			Loading...
+		</lsl_preproc_viewer>
+	</panel>
+	</tab_container>
+  <scroll_list
+    top_pad="10"
+    left="0"
+    follows="left|right|bottom"
+    height="60"
+    layout="topleft"
+    name="lsl errors"
+     width="487" />
+  <text
+    follows="left|bottom"
+    height="12"
+    layout="topleft"
+     left="0"
+    name="line_col"
+    width="128" />
+  <combo_box
+    follows="left|bottom"
+    height="23"
+    label="Insert..."
+    layout="topleft"
+    name="Insert..."
+     width="128" />
+  <button
+    follows="right|bottom"
+    height="23"
+    label="Save"
+    label_selected="Save"
+    layout="topleft"
+    top_pad="-35"
+     right="487"
+    name="Save_btn"
+    width="81" />
+  <button
+    enabled="false"
+    follows="right|bottom"
+    height="23"
+    label="Edit..."
+    layout="topleft"
+    top_pad="-23"
+     right="400"
+    name="Edit_btn"
+    width="81" />
+</panel>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index af2711776210ef55728eb9f9332d91bd4b0788c2..ab30919ed8a751b9ef104f54c67650a1dad7cc58 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -4402,4 +4402,45 @@ and report the problem.
   <string name="NotAvailableOnPlatform">Not availalbe on this platform</string>
   <string name="GridInfoTitle">GRID INFO</string>
   
+  <!-- <FS:Cron> FIRE-9335 -->
+  <!-- <LSL Preprocessor -->
+  <string name="preproc_toggle_warning">Toggling the preprocessor will not take full effect until you close and reopen this editor.</string>
+  <string name="fs_preprocessor_starting">[APP_NAME] preprocessor starting...</string>
+  <string name="fs_preprocessor_not_supported">Warning: Preprocessor not supported in this build. ([WHERE])</string>
+  <string name="fs_preprocessor_disabled_by_script_marker">[APP_NAME] preprocessor disabled by directive at line [LINENUMBER].</string>
+  <string name="fs_preprocessor_settings_list_prefix">Settings:</string>
+  <string name="fs_preprocessor_cpp_exception">[ERR_NAME] ([LINENUMBER]): [ERR_DESC]</string>
+  <string name="fs_preprocessor_lexing_exception">[SEVERITY]: [ERR_NAME] ([LINENUMBER]): [ERR_DESC]</string>
+  <string name="fs_preprocessor_exception">[ERR_NAME] ([LINENUMBER]): exception caught: [ERR_DESC]</string>
+  <string name="fs_preprocessor_error">[ERR_NAME] ([LINENUMBER]): unexpected exception caught.</string>
+  <string name="fs_preprocessor_lsl2_directive_override">Detected compile-as-LSL2 directive overriding preference setting.</string>
+  <string name="fs_preprocessor_mono_directive_override">Detected compile-as-Mono directive overriding preference setting.</string>
+  <!-- LSL Optimizer -->
+  <string name="fs_preprocessor_optimizer_start">Optimizing out unreferenced user-defined functions and global variables.</string>
+  <string name="fs_preprocessor_optimizer_regex_err">Not a valid regular expression: '[WHAT]'; LSL optimization skipped.</string>
+  <string name="fs_preprocessor_optimizer_exception">Exception caught: '[WHAT]'; LSL optimization skipped.</string>
+  <string name="fs_preprocessor_optimizer_unexpected_exception">Unexpected exception in LSL optimizer; not applied.</string>
+  <!-- LSL Compressor -->
+  <string name="fs_preprocessor_compress_start">Compressing script text by removing unnecessary space.</string>
+  <string name="fs_preprocessor_compress_regex_err">Not a valid regular expression: '[WHAT]'; LSL compression skipped.</string>
+  <string name="fs_preprocessor_compress_exception">Exception caught: '[WHAT]'; LSL compression skipped.</string>
+  <string name="fs_preprocessor_compress_unexpected_exception">Unexpected exception in LSL compressor; not applied.</string>
+  <!-- LSL Lazy lists -->
+  <string name="fs_preprocessor_lazylist_start">Applying lazy list conversion.</string>
+  <string name="fs_preprocessor_lazylist_regex_err">Not a valid regular expression: '[WHAT]'; Lazy list converter skipped.</string>
+  <string name="fs_preprocessor_lazylist_exception">Exception caught: '[WHAT]'; Lazy list converter skipped.</string>
+  <string name="fs_preprocessor_lazylist_unexpected_exception">Unexpected exception in lazy list converter; not applied.</string>
+  <!-- LSL switch statement -->
+  <string name="fs_preprocessor_switchstatement_start">Applying switch statement conversion.</string>
+  <string name="fs_preprocessor_switchstatement_regex_err">Not a valid regular expression: '[WHAT]'; Switch statement converter skipped.</string>
+  <string name="fs_preprocessor_switchstatement_exception">Exception caught: '[WHAT]'; Switch statement converter skipped.</string>
+  <string name="fs_preprocessor_switchstatement_unexpected_exception">Unexpected exception in switch statement converter; not applied.</string>
+  <!-- LSL Cache -->
+  <string name="fs_preprocessor_cache_miss">Caching included file: '[FILENAME]'</string>
+  <string name="fs_preprocessor_cache_invalidated">Included file '[FILENAME]' has changed, recaching.</string>
+  <string name="fs_preprocessor_cache_completed">Caching completed for '[FILENAME]'</string>
+  <string name="fs_preprocessor_cache_unsafe">Error: script named '[FILENAME]' isn't safe to copy to the filesystem. This include will fail.</string>
+  <string name="fs_preprocessor_caching_err">Error caching included file '[FILENAME]'</string>
+  <string name="fs_preprocessor_truncated">Warning: Preprocessor output truncated due to excessive script text size. This script will most likely not work.</string>
+  <!-- </FS:Cron> -->
 </strings>