diff --git a/doc/contributions.txt b/doc/contributions.txt
index 0954704c262dcf73e470909cc1b7bc57e537fdf6..d7a5f73ac03175f1e01f820f5aca8d6f857c5391 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -799,6 +799,7 @@ WolfPup Lowenhar
 	STORM-654
 	STORM-674
 	STORM-776
+	STORM-825
 	VWR-20741
 	VWR-20933
 Zai Lynch
diff --git a/indra/llmath/tests/m3math_test.cpp b/indra/llmath/tests/m3math_test.cpp
index 8abf61b740d21ca7bf927c7cd9f106a584e4ce5f..e4d31996a3629963bd7185efa0306d279f485000 100644
--- a/indra/llmath/tests/m3math_test.cpp
+++ b/indra/llmath/tests/m3math_test.cpp
@@ -280,7 +280,6 @@ namespace tut
 		llmat_obj.setRows(llvec1, llvec2, llvec3);
 		llmat_obj.orthogonalize();
 
-		skip("Grr, LLMatrix3::orthogonalize test is failing.  Has it ever worked?");
 		ensure("LLMatrix3::orthogonalize failed ",
 		       is_approx_equal(0.19611613f, llmat_obj.mMatrix[0][0]) &&
 		       is_approx_equal(0.78446454f, llmat_obj.mMatrix[0][1]) &&
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index d0ebf047e8a314de691a4f8e7f301ca372eab3c5..22ff362b5a66d5c2c3869e78a7614ff7d1ed45e2 100644
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -123,7 +123,9 @@ static bool have_script_upload_cap(LLUUID& object_id)
 class LLLiveLSLFile : public LLLiveFile
 {
 public:
-	LLLiveLSLFile(std::string file_path, LLLiveLSLEditor* parent);
+	typedef boost::function<bool (const std::string& filename)> change_callback_t;
+
+	LLLiveLSLFile(std::string file_path, change_callback_t change_cb);
 	~LLLiveLSLFile();
 
 	void ignoreNextUpdate() { mIgnoreNextUpdate = true; }
@@ -131,15 +133,16 @@ class LLLiveLSLFile : public LLLiveFile
 protected:
 	/*virtual*/ bool loadFile();
 
-	LLLiveLSLEditor*	mParent;
+	change_callback_t	mOnChangeCallback;
 	bool				mIgnoreNextUpdate;
 };
 
-LLLiveLSLFile::LLLiveLSLFile(std::string file_path, LLLiveLSLEditor* parent)
-:	mParent(parent)
+LLLiveLSLFile::LLLiveLSLFile(std::string file_path, change_callback_t change_cb)
+:	mOnChangeCallback(change_cb)
 ,	mIgnoreNextUpdate(false)
 ,	LLLiveFile(file_path, 1.0)
 {
+	llassert(mOnChangeCallback);
 }
 
 LLLiveLSLFile::~LLLiveLSLFile()
@@ -155,14 +158,7 @@ bool LLLiveLSLFile::loadFile()
 		return true;
 	}
 
-	if (!mParent->loadScriptText(filename()))
-	{
-		return false;
-	}
-
-	// Disable sync to avoid recursive load->save->load calls.
-	mParent->saveIfNeeded(false);
-	return true;
+	return mOnChangeCallback(filename());
 }
 
 /// ---------------------------------------------------------------------------
@@ -327,11 +323,11 @@ struct LLSECKeywordCompare
 };
 
 LLScriptEdCore::LLScriptEdCore(
+	LLScriptEdContainer* container,
 	const std::string& sample,
 	const LLHandle<LLFloater>& floater_handle,
 	void (*load_callback)(void*),
 	void (*save_callback)(void*, BOOL),
-	void (*edit_callback)(void*),
 	void (*search_replace_callback) (void* userdata),
 	void* userdata,
 	S32 bottom_pad)
@@ -341,19 +337,21 @@ LLScriptEdCore::LLScriptEdCore(
 	mEditor( NULL ),
 	mLoadCallback( load_callback ),
 	mSaveCallback( save_callback ),
-	mEditCallback( edit_callback ),
 	mSearchReplaceCallback( search_replace_callback ),
 	mUserdata( userdata ),
 	mForceClose( FALSE ),
 	mLastHelpToken(NULL),
 	mLiveHelpHistorySize(0),
 	mEnableSave(FALSE),
+	mLiveFile(NULL),
+	mContainer(container),
 	mHasScriptData(FALSE)
 {
 	setFollowsAll();
 	setBorderVisible(FALSE);
 
 	setXMLFilename("panel_script_ed.xml");
+	llassert_always(mContainer != NULL);
 }
 
 LLScriptEdCore::~LLScriptEdCore()
@@ -367,6 +365,8 @@ LLScriptEdCore::~LLScriptEdCore()
 		script_search->closeFloater();
 		delete script_search;
 	}
+
+	delete mLiveFile;
 }
 
 BOOL LLScriptEdCore::postBuild()
@@ -381,7 +381,7 @@ BOOL LLScriptEdCore::postBuild()
 
 	childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this);
 	childSetAction("Save_btn", boost::bind(&LLScriptEdCore::doSave,this,FALSE));
-	childSetAction("Edit_btn", boost::bind(&LLScriptEdCore::onEditButtonClick, this));
+	childSetAction("Edit_btn", boost::bind(&LLScriptEdCore::openInExternalEditor, this));
 
 	initMenu();
 
@@ -514,6 +514,79 @@ void LLScriptEdCore::setScriptText(const std::string& text, BOOL is_valid)
 	}
 }
 
+bool LLScriptEdCore::loadScriptText(const std::string& filename)
+{
+	if (filename.empty())
+	{
+		llwarns << "Empty file name" << llendl;
+		return false;
+	}
+
+	LLFILE* file = LLFile::fopen(filename, "rb");		/*Flawfinder: ignore*/
+	if (!file)
+	{
+		llwarns << "Error opening " << filename << llendl;
+		return false;
+	}
+
+	// read in the whole file
+	fseek(file, 0L, SEEK_END);
+	size_t file_length = (size_t) ftell(file);
+	fseek(file, 0L, SEEK_SET);
+	char* buffer = new char[file_length+1];
+	size_t nread = fread(buffer, 1, file_length, file);
+	if (nread < file_length)
+	{
+		llwarns << "Short read" << llendl;
+	}
+	buffer[nread] = '\0';
+	fclose(file);
+
+	mEditor->setText(LLStringExplicit(buffer));
+	delete[] buffer;
+
+	return true;
+}
+
+bool LLScriptEdCore::writeToFile(const std::string& filename)
+{
+	LLFILE* fp = LLFile::fopen(filename, "wb");
+	if (!fp)
+	{
+		llwarns << "Unable to write to " << filename << llendl;
+
+		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;
+	}
+
+	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;
+}
+
+void LLScriptEdCore::sync()
+{
+	// Sync with external editor.
+	std::string tmp_file = mContainer->getTmpFileName();
+	llstat s;
+	if (LLFile::stat(tmp_file, &s) == 0) // file exists
+	{
+		if (mLiveFile) mLiveFile->ignoreNextUpdate();
+		writeToFile(tmp_file);
+	}
+}
+
 bool LLScriptEdCore::hasChanged()
 {
 	if (!mEditor) return false;
@@ -690,6 +763,12 @@ BOOL LLScriptEdCore::canClose()
 	}
 }
 
+void LLScriptEdCore::setEnableEditing(bool enable)
+{
+	mEditor->setEnabled(enable);
+	getChildView("Edit_btn")->setEnabled(enable);
+}
+
 bool LLScriptEdCore::handleSaveChangesDialog(const LLSD& notification, const LLSD& response )
 {
 	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
@@ -862,11 +941,31 @@ void LLScriptEdCore::doSave( BOOL close_after_save )
 	}
 }
 
-void LLScriptEdCore::onEditButtonClick()
+void LLScriptEdCore::openInExternalEditor()
 {
-	if (mEditCallback)
+	delete mLiveFile; // deletes file
+
+	// Save the script to a temporary file.
+	std::string filename = mContainer->getTmpFileName();
+	writeToFile(filename);
+
+	// Start watching file changes.
+	mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLScriptEdContainer::onExternalChange, mContainer, _1));
+	mLiveFile->addToEventTimer();
+
+	// Open it in external editor.
 	{
-		mEditCallback(mUserdata);
+		LLExternalEditor ed;
+
+		if (!ed.setCommand("LL_SCRIPT_EDITOR"))
+		{
+			std::string msg = "Select an editor by setting the environment variable LL_SCRIPT_EDITOR "
+				"or the ExternalEditor setting"; // *TODO: localize
+			LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg));
+			return;
+		}
+
+		ed.run(filename);
 	}
 }
 
@@ -982,6 +1081,43 @@ BOOL LLScriptEdCore::handleKeyHere(KEY key, MASK mask)
 	return FALSE;
 }
 
+/// ---------------------------------------------------------------------------
+/// LLScriptEdContainer
+/// ---------------------------------------------------------------------------
+
+LLScriptEdContainer::LLScriptEdContainer(const LLSD& key)
+:	LLPreview(key)
+,	mScriptEd(NULL)
+{
+}
+
+std::string LLScriptEdContainer::getTmpFileName()
+{
+	// Take script inventory item id (within the object inventory)
+	// to consideration so that it's possible to edit multiple scripts
+	// in the same object inventory simultaneously (STORM-781).
+	std::string script_id = mObjectUUID.asString() + "_" + mItemUUID.asString();
+
+	// Use MD5 sum to make the file name shorter and not exceed maximum path length.
+	char script_id_hash_str[33];               /* Flawfinder: ignore */
+	LLMD5 script_id_hash((const U8 *)script_id.c_str());
+	script_id_hash.hex_digest(script_id_hash_str);
+
+	return std::string(LLFile::tmpdir()) + "sl_script_" + script_id_hash_str + ".lsl";
+}
+
+bool LLScriptEdContainer::onExternalChange(const std::string& filename)
+{
+	if (!mScriptEd->loadScriptText(filename))
+	{
+		return false;
+	}
+
+	// Disable sync to avoid recursive load->save->load calls.
+	saveIfNeeded(false);
+	return true;
+}
+
 /// ---------------------------------------------------------------------------
 /// LLPreviewLSL
 /// ---------------------------------------------------------------------------
@@ -1005,11 +1141,11 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata)
 	LLPreviewLSL *self = (LLPreviewLSL*)userdata;
 
 	self->mScriptEd =  new LLScriptEdCore(
+								   self,
 								   HELLO_LSL,
 								   self->getHandle(),
 								   LLPreviewLSL::onLoad,
 								   LLPreviewLSL::onSave,
-								   NULL, // no edit callback
 								   LLPreviewLSL::onSearchReplace,
 								   self,
 								   0);
@@ -1019,7 +1155,7 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata)
 
 
 LLPreviewLSL::LLPreviewLSL(const LLSD& key )
-  : LLPreview( key ),
+:	LLScriptEdContainer(key),
 	mPendingUploads(0)
 {
 	mFactoryMap["script panel"] = LLCallbackMap(LLPreviewLSL::createScriptEdPanel, this);
@@ -1110,7 +1246,6 @@ void LLPreviewLSL::loadAsset()
 		{
 			mScriptEd->setScriptText(mScriptEd->getString("can_not_view"), FALSE);
 			mScriptEd->mEditor->makePristine();
-			mScriptEd->mEditor->setEnabled(FALSE);
 			mScriptEd->mFunctions->setEnabled(FALSE);
 			mAssetStatus = PREVIEW_ASSET_LOADED;
 		}
@@ -1120,6 +1255,7 @@ void LLPreviewLSL::loadAsset()
 	else
 	{
 		mScriptEd->setScriptText(std::string(HELLO_LSL), TRUE);
+		mScriptEd->setEnableEditing(TRUE);
 		mAssetStatus = PREVIEW_ASSET_LOADED;
 	}
 }
@@ -1166,7 +1302,7 @@ void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save)
 // Save needs to compile the text in the buffer. If the compile
 // succeeds, then save both assets out to the database. If the compile
 // fails, go ahead and save the text anyway.
-void LLPreviewLSL::saveIfNeeded()
+void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/)
 {
 	// llinfos << "LLPreviewLSL::saveIfNeeded()" << llendl;
 	if(!mScriptEd->hasChanged())
@@ -1185,23 +1321,13 @@ void LLPreviewLSL::saveIfNeeded()
 	std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
 	std::string filename = filepath + ".lsl";
 
-	LLFILE* fp = LLFile::fopen(filename, "wb");
-	if(!fp)
-	{
-		llwarns << "Unable to write to " << filename << llendl;
+	mScriptEd->writeToFile(filename);
 
-		LLSD row;
-		row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?";
-		row["columns"][0]["font"] = "SANSSERIF_SMALL";
-		mScriptEd->mErrorList->addElement(row);
-		return;
+	if (sync)
+	{
+		mScriptEd->sync();
 	}
 
-	std::string utf8text = mScriptEd->mEditor->getText();
-	fputs(utf8text.c_str(), fp);
-	fclose(fp);
-	fp = NULL;
-
 	const LLInventoryItem *inv_item = getItem();
 	// save it out to asset server
 	std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent");
@@ -1433,7 +1559,7 @@ void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAsset
 			{
 				is_modifiable = TRUE;		
 			}
-			preview->mScriptEd->mEditor->setEnabled(is_modifiable);
+			preview->mScriptEd->setEnableEditing(is_modifiable);
 			preview->mAssetStatus = PREVIEW_ASSET_LOADED;
 		}
 		else
@@ -1474,11 +1600,11 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata)
 	LLLiveLSLEditor *self = (LLLiveLSLEditor*)userdata;
 
 	self->mScriptEd =  new LLScriptEdCore(
+								   self,
 								   HELLO_LSL,
 								   self->getHandle(),
 								   &LLLiveLSLEditor::onLoad,
 								   &LLLiveLSLEditor::onSave,
-								   &LLLiveLSLEditor::onEdit,
 								   &LLLiveLSLEditor::onSearchReplace,
 								   self,
 								   0);
@@ -1488,14 +1614,12 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata)
 
 
 LLLiveLSLEditor::LLLiveLSLEditor(const LLSD& key) :
-	LLPreview(key),
-	mScriptEd(NULL),
+	LLScriptEdContainer(key),
 	mAskedForRunningInfo(FALSE),
 	mHaveRunningInfo(FALSE),
 	mCloseAfterSave(FALSE),
 	mPendingUploads(0),
 	mIsModifiable(FALSE),
-	mLiveFile(NULL),
 	mIsNew(false)
 {
 	mFactoryMap["script ed panel"] = LLCallbackMap(LLLiveLSLEditor::createScriptEdPanel, this);
@@ -1519,11 +1643,6 @@ BOOL LLLiveLSLEditor::postBuild()
 	return LLPreview::postBuild();
 }
 
-LLLiveLSLEditor::~LLLiveLSLEditor()
-{
-	delete mLiveFile;
-}
-
 // virtual
 void LLLiveLSLEditor::callbackLSLCompileSucceeded(const LLUUID& task_id,
 												  const LLUUID& item_id,
@@ -1580,7 +1699,6 @@ void LLLiveLSLEditor::loadAsset()
 				mItem = new LLViewerInventoryItem(item);
 				mScriptEd->setScriptText(getString("not_allowed"), FALSE);
 				mScriptEd->mEditor->makePristine();
-				mScriptEd->mEditor->setEnabled(FALSE);
 				mScriptEd->enableSave(FALSE);
 				mAssetStatus = PREVIEW_ASSET_LOADED;
 			}
@@ -1618,10 +1736,6 @@ void LLLiveLSLEditor::loadAsset()
 			mIsModifiable = item && gAgent.allowOperation(PERM_MODIFY, 
 										item->getPermissions(),
 				   						GP_OBJECT_MANIPULATE);
-			if(!mIsModifiable)
-			{
-				mScriptEd->mEditor->setEnabled(FALSE);
-			}
 			
 			// This is commented out, because we don't completely
 			// handle script exports yet.
@@ -1677,6 +1791,7 @@ void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id,
 		if( LL_ERR_NOERR == status )
 		{
 			instance->loadScriptText(vfs, asset_id, type);
+			instance->mScriptEd->setEnableEditing(TRUE);
 			instance->mAssetStatus = PREVIEW_ASSET_LOADED;
 		}
 		else
@@ -1703,40 +1818,6 @@ void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id,
 	delete xored_id;
 }
 
- bool LLLiveLSLEditor::loadScriptText(const std::string& filename)
- {
- 	if (filename.empty())
- 	{
- 		llwarns << "Empty file name" << llendl;
- 		return false;
- 	}
-
- 	LLFILE* file = LLFile::fopen(filename, "rb");		/*Flawfinder: ignore*/
- 	if (!file)
- 	{
- 		llwarns << "Error opening " << filename << llendl;
- 		return false;
- 	}
-
- 	// read in the whole file
-	fseek(file, 0L, SEEK_END);
-	size_t file_length = (size_t) ftell(file);
-	fseek(file, 0L, SEEK_SET);
-	char* buffer = new char[file_length+1];
-	size_t nread = fread(buffer, 1, file_length, file);
-	if (nread < file_length)
-	{
-		llwarns << "Short read" << llendl;
-	}
-	buffer[nread] = '\0';
-	fclose(file);
-	mScriptEd->mEditor->setText(LLStringExplicit(buffer));
-	//mScriptEd->mEditor->makePristine();
-	delete[] buffer;
-
-	return true;
- }
-
 void LLLiveLSLEditor::loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type)
 {
 	LLVFile file(vfs, uuid, type);
@@ -1890,7 +1971,8 @@ LLLiveLSLSaveData::LLLiveLSLSaveData(const LLUUID& id,
 	mItem = new LLViewerInventoryItem(item);
 }
 
-void LLLiveLSLEditor::saveIfNeeded(bool sync)
+// virtual
+void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/)
 {
 	LLViewerObject* object = gObjectList.findObject(mObjectUUID);
 	if(!object)
@@ -1941,18 +2023,11 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync)
 	mItem->setAssetUUID(asset_id);
 	mItem->setTransactionID(tid);
 
-	writeToFile(filename);
+	mScriptEd->writeToFile(filename);
 
 	if (sync)
 	{
-		// Sync with external ed2itor.
-		std::string tmp_file = getTmpFileName();
-		llstat s;
-		if (LLFile::stat(tmp_file, &s) == 0) // file exists
-		{
-			if (mLiveFile) mLiveFile->ignoreNextUpdate();
-			writeToFile(tmp_file);
-		}
+		mScriptEd->sync();
 	}
 	
 	// save it out to asset server
@@ -1970,83 +2045,6 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync)
 	}
 }
 
-void LLLiveLSLEditor::openExternalEditor()
-{
-	LLViewerObject* object = gObjectList.findObject(mObjectUUID);
-	if(!object)
-	{
-		LLNotificationsUtil::add("SaveScriptFailObjectNotFound");
-		return;
-	}
-
-	delete mLiveFile; // deletes file
-
-	// Save the script to a temporary file.
-	std::string filename = getTmpFileName();
-	writeToFile(filename);
-
-	// Start watching file changes.
-	mLiveFile = new LLLiveLSLFile(filename, this);
-	mLiveFile->addToEventTimer();
-
-	// Open it in external editor.
-	{
-		LLExternalEditor ed;
-
-		if (!ed.setCommand("LL_SCRIPT_EDITOR"))
-		{
-			std::string msg = "Select an editor by setting the environment variable LL_SCRIPT_EDITOR "
-				"or the ExternalEditor setting"; // *TODO: localize
-			LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg));
-			return;
-		}
-
-		ed.run(filename);
-	}
-}
-
-bool LLLiveLSLEditor::writeToFile(const std::string& filename)
-{
-	LLFILE* fp = LLFile::fopen(filename, "wb");
-	if (!fp)
-	{
-		llwarns << "Unable to write to " << filename << llendl;
-
-		LLSD row;
-		row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?";
-		row["columns"][0]["font"] = "SANSSERIF_SMALL";
-		mScriptEd->mErrorList->addElement(row);
-		return false;
-	}
-
-	std::string utf8text = mScriptEd->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;
-}
-
-std::string LLLiveLSLEditor::getTmpFileName()
-{
-	// Take script inventory item id (within the object inventory)
-	// to consideration so that it's possible to edit multiple scripts
-	// in the same object inventory simultaneously (STORM-781).
-	std::string script_id = mObjectUUID.asString() + "_" + mItemUUID.asString();
-
-	// Use MD5 sum to make the file name shorter and not exceed maximum path length.
-	char script_id_hash_str[33];               /* Flawfinder: ignore */
-	LLMD5 script_id_hash((const U8 *)script_id.c_str());
-	script_id_hash.hex_digest(script_id_hash_str);
-
-	return std::string(LLFile::tmpdir()) + "sl_script_" + script_id_hash_str + ".lsl";
-}
-
 void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url,
 										 const std::string& filename,
 										 const LLUUID& task_id,
@@ -2270,13 +2268,6 @@ void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save)
 }
 
 
-// static
-void LLLiveLSLEditor::onEdit(void* userdata)
-{
-	LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
-	self->openExternalEditor();
-}
-
 // static
 void LLLiveLSLEditor::processScriptRunningReply(LLMessageSystem* msg, void**)
 {
diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h
index d35c6b85283b0445ee09b2b69f3f414f76b64544..f86be615c44ce396f69d295b7480ae545aeadf13 100644
--- a/indra/newview/llpreviewscript.h
+++ b/indra/newview/llpreviewscript.h
@@ -48,6 +48,7 @@ class LLFloaterScriptSearch;
 class LLKeywordToken;
 class LLVFS;
 class LLViewerInventoryItem;
+class LLScriptEdContainer;
 
 // Inner, implementation class.  LLPreviewScript and LLLiveLSLEditor each own one of these.
 class LLScriptEdCore : public LLPanel
@@ -56,17 +57,20 @@ class LLScriptEdCore : public LLPanel
 	friend class LLPreviewLSL;
 	friend class LLLiveLSLEditor;
 	friend class LLFloaterScriptSearch;
+	friend class LLScriptEdContainer;
 
-public:
+protected:
+	// Supposed to be invoked only by the container.
 	LLScriptEdCore(
+		LLScriptEdContainer* container,
 		const std::string& sample,
 		const LLHandle<LLFloater>& floater_handle,
 		void (*load_callback)(void* userdata),
 		void (*save_callback)(void* userdata, BOOL close_after_save),
-		void (*edit_callback)(void*),
 		void (*search_replace_callback)(void* userdata),
 		void* userdata,
 		S32 bottom_pad = 0);	// pad below bottom row of buttons
+public:
 	~LLScriptEdCore();
 	
 	void			initMenu();
@@ -74,15 +78,19 @@ class LLScriptEdCore : public LLPanel
 	virtual void	draw();
 	/*virtual*/	BOOL	postBuild();
 	BOOL			canClose();
+	void			setEnableEditing(bool enable);
 
 	void            setScriptText(const std::string& text, BOOL is_valid);
+	bool			loadScriptText(const std::string& filename);
+	bool			writeToFile(const std::string& filename);
+	void			sync();
 	
 	void			doSave( BOOL close_after_save );
 
 	bool			handleSaveChangesDialog(const LLSD& notification, const LLSD& response);
 	bool			handleReloadFromServerDialog(const LLSD& notification, const LLSD& response);
 
-	void			onEditButtonClick();
+	void			openInExternalEditor();
 
 	static void		onCheckLock(LLUICtrl*, void*);
 	static void		onHelpComboCommit(LLUICtrl* ctrl, void* userdata);
@@ -118,7 +126,6 @@ class LLScriptEdCore : public LLPanel
 	LLTextEditor*	mEditor;
 	void			(*mLoadCallback)(void* userdata);
 	void			(*mSaveCallback)(void* userdata, BOOL close_after_save);
-	void			(*mEditCallback)(void* userdata);
 	void			(*mSearchReplaceCallback) (void* userdata);
 	void*			mUserdata;
 	LLComboBox		*mFunctions;
@@ -132,11 +139,28 @@ class LLScriptEdCore : public LLPanel
 	S32				mLiveHelpHistorySize;
 	BOOL			mEnableSave;
 	BOOL			mHasScriptData;
+	LLLiveLSLFile*	mLiveFile;
+
+	LLScriptEdContainer* mContainer; // parent view
 };
 
+class LLScriptEdContainer : public LLPreview
+{
+	friend class LLScriptEdCore;
+
+public:
+	LLScriptEdContainer(const LLSD& key);
+
+protected:
+	std::string		getTmpFileName();
+	bool			onExternalChange(const std::string& filename);
+	virtual void	saveIfNeeded(bool sync = true) = 0;
+
+	LLScriptEdCore*		mScriptEd;
+};
 
 // Used to view and edit a LSL from your inventory.
-class LLPreviewLSL : public LLPreview
+class LLPreviewLSL : public LLScriptEdContainer
 {
 public:
 	LLPreviewLSL(const LLSD& key );
@@ -150,7 +174,7 @@ class LLPreviewLSL : public LLPreview
 	void closeIfNeeded();
 
 	virtual void loadAsset();
-	void saveIfNeeded();
+	/*virtual*/ void saveIfNeeded(bool sync = true);
 	void uploadAssetViaCaps(const std::string& url,
 							const std::string& filename, 
 							const LLUUID& item_id);
@@ -174,7 +198,6 @@ class LLPreviewLSL : public LLPreview
 
 protected:
 
-	LLScriptEdCore* mScriptEd;
 	// Can safely close only after both text and bytecode are uploaded
 	S32 mPendingUploads;
 
@@ -182,12 +205,11 @@ class LLPreviewLSL : public LLPreview
 
 
 // Used to view and edit an LSL that is attached to an object.
-class LLLiveLSLEditor : public LLPreview
+class LLLiveLSLEditor : public LLScriptEdContainer
 {
 	friend class LLLiveLSLFile;
 public: 
 	LLLiveLSLEditor(const LLSD& key);
-	~LLLiveLSLEditor();
 
 
 	static void processScriptRunningReply(LLMessageSystem* msg, void**);
@@ -208,10 +230,7 @@ class LLLiveLSLEditor : public LLPreview
 
 	virtual void loadAsset();
 	void loadAsset(BOOL is_new);
-	void saveIfNeeded(bool sync = true);
-	void openExternalEditor();
-	std::string getTmpFileName();
-	bool writeToFile(const std::string& filename);
+	/*virtual*/ void saveIfNeeded(bool sync = true);
 	void uploadAssetViaCaps(const std::string& url,
 							const std::string& filename, 
 							const LLUUID& task_id,
@@ -227,7 +246,6 @@ class LLLiveLSLEditor : public LLPreview
 	static void onSearchReplace(void* userdata);
 	static void onLoad(void* userdata);
 	static void onSave(void* userdata, BOOL close_after_save);
-	static void onEdit(void* userdata);
 
 	static void onLoadComplete(LLVFS *vfs, const LLUUID& asset_uuid,
 							   LLAssetType::EType type,
@@ -237,7 +255,6 @@ class LLLiveLSLEditor : public LLPreview
 	static void onRunningCheckboxClicked(LLUICtrl*, void* userdata);
 	static void onReset(void* userdata);
 
- 	bool loadScriptText(const std::string& filename);
 	void loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type);
 
 	static void onErrorList(LLUICtrl*, void* user_data);
@@ -248,7 +265,6 @@ class LLLiveLSLEditor : public LLPreview
 
 private:
 	bool				mIsNew;
-	LLScriptEdCore*		mScriptEd;
 	//LLUUID mTransmitID;
 	LLCheckBoxCtrl*		mRunningCheckbox;
 	BOOL				mAskedForRunningInfo;
@@ -263,7 +279,6 @@ class LLLiveLSLEditor : public LLPreview
 	
 	LLCheckBoxCtrl*	mMonoCheckbox;
 	BOOL mIsModifiable;
-	LLLiveLSLFile*		mLiveFile;
 };
 
 #endif  // LL_LLPREVIEWSCRIPT_H
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 a041c9b2293ffd777af8f2ae999622c6e9171b04..627b12cfe17a71f088ff2293474425d03207f7ca 100644
--- a/indra/newview/skins/default/xui/en/panel_script_ed.xml
+++ b/indra/newview/skins/default/xui/en/panel_script_ed.xml
@@ -180,6 +180,7 @@
      name="Save_btn"
      width="81" />
     <button
+     enabled="false"
      follows="right|bottom"
      height="23"
      label="Edit..."