diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 7757ba8f0c15fed751f2383270f74389eb00bac8..bc91c83abe5741122dca7e04b897e9d05bcd4a77 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -296,6 +296,7 @@ set(viewer_SOURCE_FILES
     llfloaterpathfindingconsole.cpp
     llfloaterpathfindinglinksets.cpp
     llfloaterpathfindingobjects.cpp
+    llfloaterparticleeditor.cpp
     llfloaterpay.cpp
     llfloaterperms.cpp
     llfloaterpostprocess.cpp
@@ -929,6 +930,7 @@ set(viewer_HEADER_FILES
     llfloaterobjectweights.h
     llfloateropenobject.h
     llfloateroutbox.h
+    llfloaterparticleeditor.h
     llfloaterpathfindingcharacters.h
     llfloaterpathfindingconsole.h
     llfloaterpathfindinglinksets.h
diff --git a/indra/newview/llfloaterparticleeditor.cpp b/indra/newview/llfloaterparticleeditor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ef190d044cceafb1d526c1b3edeb44b126722b95
--- /dev/null
+++ b/indra/newview/llfloaterparticleeditor.cpp
@@ -0,0 +1,646 @@
+/** 
+ * @file llfloaterparticleeditor.cpp
+ * @brief Particle Editor
+ *
+ * Copyright (C) 2011, Zi Ree @ Second Life
+ * Copyright (C) 2015, Cinder Roxley <cinder@sdf.org>
+ * 
+ * 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
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llfloaterparticleeditor.h"
+
+#include "llagent.h"
+#include "llappviewer.h"
+#include "llassetuploadresponders.h"
+#include "llcheckboxctrl.h"
+#include "llclipboard.h"
+#include "llcolorswatch.h"
+#include "llcombobox.h"
+#include "lldir.h"
+#include "llfoldertype.h"
+#include "llhttpclient.h"
+#include "llinventorymodel.h"
+#include "llinventorytype.h"
+#include "llnotificationsutil.h"
+#include "llpermissions.h"
+#include "llpreviewscript.h"
+#include "llsd.h"
+#include "lltexturectrl.h"
+#include "lltoolmgr.h"
+#include "lltoolobjpicker.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewerpartsim.h"
+#include "llviewerpartsource.h"
+#include "llviewerregion.h"
+#include "llviewertexture.h"
+#include "llwindow.h"
+
+struct lsl_part_st {
+	U8 flag;
+	const char* script_const;
+	lsl_part_st(const U8 f, const char* sc)
+		{ flag = f, script_const = sc; }
+};
+
+static const std::map<std::string, lsl_part_st> sParticlePatterns{
+	{"drop", lsl_part_st(LLPartSysData::LL_PART_SRC_PATTERN_DROP, "PSYS_SRC_PATTERN_DROP")},
+	{"explode", lsl_part_st(LLPartSysData::LL_PART_SRC_PATTERN_EXPLODE, "PSYS_SRC_PATTERN_EXPLODE")},
+	{"angle", lsl_part_st(LLPartSysData::LL_PART_SRC_PATTERN_ANGLE, "PSYS_SRC_PATTERN_ANGLE")},
+	{"angle_cone", lsl_part_st(LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE, "PSYS_SRC_PATTERN_ANGLE_CONE")},
+	{"angle_cone_empty", lsl_part_st(LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE_EMPTY, "PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY")}
+};
+
+static const std::map<std::string, lsl_part_st> sParticleBlends{
+	{"blend_one", lsl_part_st(LLPartData::LL_PART_BF_ONE, "PSYS_PART_BF_ONE")},
+	{"blend_zero", lsl_part_st(LLPartData::LL_PART_BF_ZERO, "PSYS_PART_BF_ZERO")},
+	{"blend_dest_color", lsl_part_st(LLPartData::LL_PART_BF_DEST_COLOR, "PSYS_PART_BF_DEST_COLOR")},
+	{"blend_src_color", lsl_part_st(LLPartData::LL_PART_BF_SOURCE_COLOR, "PSYS_PART_BF_SOURCE_COLOR")},
+	{"blend_one_minus_dest_color", lsl_part_st(LLPartData::LL_PART_BF_ONE_MINUS_DEST_COLOR, "PSYS_PART_BF_ONE_MINUS_DEST_COLOR")},
+	{"blend_one_minus_src_color", lsl_part_st(LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_COLOR, "PSYS_PART_BF_SOURCE_ALPHA")},
+	{"blend_src_alpha", lsl_part_st(LLPartData::LL_PART_BF_SOURCE_ALPHA, "PSYS_PART_BF_SOURCE_ALPHA")},
+	{"blend_one_minus_src_alpha", lsl_part_st(LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA, "PSYS_PART_BF_ONE_MINUS_SOURCE_ALPHA")}
+};
+
+LLFloaterParticleEditor::LLFloaterParticleEditor(const LLSD& key)
+:	LLFloater(key), mObject(nullptr), mParticleScriptInventoryItem(nullptr)
+,	mPatternTypeCombo(nullptr), mTexturePicker(nullptr)
+,	mBurstRateCtrl(nullptr), mBurstCountCtrl(nullptr), mBurstRadiusCtrl(nullptr)
+,	mAngleBeginCtrl(nullptr), mAngleEndCtrl(nullptr), mBurstSpeedMinCtrl(nullptr)
+,	mBurstSpeedMaxCtrl(nullptr), mStartAlphaCtrl(nullptr), mEndAlphaCtrl(nullptr)
+,	mScaleStartXCtrl(nullptr), mScaleStartYCtrl(nullptr), mScaleEndXCtrl(nullptr)
+,	mScaleEndYCtrl(nullptr), mSourceMaxAgeCtrl(nullptr), mParticlesMaxAgeCtrl(nullptr)
+,	mStartGlowCtrl(nullptr), mEndGlowCtrl(nullptr), mBlendFuncSrcCombo(nullptr)
+,	mBlendFuncDestCombo(nullptr), mBounceCheckBox(nullptr), mEmissiveCheckBox(nullptr)
+,	mFollowSourceCheckBox(nullptr), mFollowVelocityCheckBox(nullptr), mInterpolateColorCheckBox(nullptr)
+,	mInterpolateScaleCheckBox(nullptr), mTargetPositionCheckBox(nullptr), mTargetLinearCheckBox(nullptr)
+,	mWindCheckBox(nullptr), mRibbonCheckBox(nullptr), mAcellerationXCtrl(nullptr)
+,	mAcellerationYCtrl(nullptr), mAcellerationZCtrl(nullptr), mOmegaXCtrl(nullptr)
+,	mOmegaYCtrl(nullptr), mOmegaZCtrl(nullptr), mStartColorSelector(nullptr)
+,	mEndColorSelector(nullptr), mTargetKeyInput(nullptr), mClearTargetButton(nullptr)
+,	mPickTargetButton(nullptr), mInjectScriptButton(nullptr), mCopyToLSLButton(nullptr)
+{
+	mCommitCallbackRegistrar.add("Particle.Edit", boost::bind(&LLFloaterParticleEditor::onParameterChange, this));
+	mDefaultParticleTexture = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c");
+}
+
+LLFloaterParticleEditor::~LLFloaterParticleEditor()
+{
+	clearParticles();
+}
+
+BOOL LLFloaterParticleEditor::postBuild()
+{
+	LLPanel* panel = getChild<LLPanel>("burst_panel");
+	mBurstRateCtrl = panel->getChild<LLUICtrl>("burst_rate");
+	mBurstCountCtrl = panel->getChild<LLUICtrl>("burst_count");
+	mBurstRadiusCtrl = panel->getChild<LLUICtrl>("burst_radius");
+	mBurstSpeedMinCtrl = panel->getChild<LLUICtrl>("burst_speed_min");
+	mBurstSpeedMaxCtrl = panel->getChild<LLUICtrl>("burst_speed_max");
+	mSourceMaxAgeCtrl = panel->getChild<LLUICtrl>("source_max_age");
+	mParticlesMaxAgeCtrl = panel->getChild<LLUICtrl>("particle_max_age");
+	
+	panel = getChild<LLPanel>("angle_panel");
+	mAngleBeginCtrl = panel->getChild<LLUICtrl>("angle_begin");
+	mAngleEndCtrl = panel->getChild<LLUICtrl>("angle_end");
+	mScaleStartXCtrl = panel->getChild<LLUICtrl>("scale_start_x");
+	mScaleStartYCtrl = panel->getChild<LLUICtrl>("scale_start_y");
+	mScaleEndXCtrl = panel->getChild<LLUICtrl>("scale_end_x");
+	mScaleEndYCtrl = panel->getChild<LLUICtrl>("scale_end_y");
+	
+	panel = getChild<LLPanel>("alpha_panel");
+	mStartAlphaCtrl = panel->getChild<LLUICtrl>("start_alpha");
+	mEndAlphaCtrl = panel->getChild<LLUICtrl>("end_alpha");
+	mStartGlowCtrl = panel->getChild<LLUICtrl>("start_glow");
+	mEndGlowCtrl = panel->getChild<LLUICtrl>("end_glow");
+	
+	panel = getChild<LLPanel>("omega_panel");
+	mAcellerationXCtrl = panel->getChild<LLUICtrl>("acceleration_x");
+	mAcellerationYCtrl = panel->getChild<LLUICtrl>("acceleration_y");
+	mAcellerationZCtrl = panel->getChild<LLUICtrl>("acceleration_z");
+	mOmegaXCtrl = panel->getChild<LLUICtrl>("omega_x");
+	mOmegaYCtrl = panel->getChild<LLUICtrl>("omega_y");
+	mOmegaZCtrl = panel->getChild<LLUICtrl>("omega_z");
+	
+	panel = getChild<LLPanel>("color_panel");
+	mStartColorSelector = panel->getChild<LLColorSwatchCtrl>("start_color_selector");
+	mEndColorSelector = panel->getChild<LLColorSwatchCtrl>("end_color_selector");
+	mTexturePicker = panel->getChild<LLTextureCtrl>("texture_picker");
+	mBlendFuncSrcCombo = panel->getChild<LLComboBox>("blend_func_src_combo");
+	mBlendFuncDestCombo = panel->getChild<LLComboBox>("blend_func_dest_combo");
+	
+	panel = getChild<LLPanel>("checkbox_panel");
+	mPatternTypeCombo = panel->getChild<LLComboBox>("pattern_type_combo");
+	mBounceCheckBox = panel->getChild<LLCheckBoxCtrl>("bounce_checkbox");
+	mEmissiveCheckBox = panel->getChild<LLCheckBoxCtrl>("emissive_checkbox");
+	mFollowSourceCheckBox = panel->getChild<LLCheckBoxCtrl>("follow_source_checkbox");
+	mFollowVelocityCheckBox = panel->getChild<LLCheckBoxCtrl>("follow_velocity_checkbox");
+	mInterpolateColorCheckBox = panel->getChild<LLCheckBoxCtrl>("interpolate_color_checkbox");
+	mInterpolateScaleCheckBox = panel->getChild<LLCheckBoxCtrl>("interpolate_scale_checkbox");
+	mTargetPositionCheckBox = panel->getChild<LLCheckBoxCtrl>("target_position_checkbox");
+	mTargetLinearCheckBox = panel->getChild<LLCheckBoxCtrl>("target_linear_checkbox");
+	mWindCheckBox = panel->getChild<LLCheckBoxCtrl>("wind_checkbox");
+	mRibbonCheckBox = panel->getChild<LLCheckBoxCtrl>("ribbon_checkbox");
+
+	mTargetKeyInput = panel->getChild<LLUICtrl>("target_key_input");
+	mClearTargetButton = panel->getChild<LLButton>("clear_target_button");
+	mPickTargetButton = panel->getChild<LLButton>("pick_target_button");
+	mInjectScriptButton = panel->getChild<LLButton>("inject_button");
+	mCopyToLSLButton = panel->getChild<LLButton>("copy_button");
+	
+	mClearTargetButton->setCommitCallback(boost::bind(&LLFloaterParticleEditor::onClickClearTarget, this));
+	mPickTargetButton->setCommitCallback(boost::bind(&LLFloaterParticleEditor::onClickTargetPicker, this));
+	mInjectScriptButton->setCommitCallback(boost::bind(&LLFloaterParticleEditor::onClickInject, this));
+	mCopyToLSLButton->setCommitCallback(boost::bind(&LLFloaterParticleEditor::onClickCopy, this));
+
+	mBlendFuncSrcCombo->setValue("blend_src_alpha");
+	mBlendFuncDestCombo->setValue("blend_one_minus_src_alpha");
+
+	onParameterChange();
+
+	return TRUE;
+}
+
+void LLFloaterParticleEditor::clearParticles()
+{
+	if (!mObject) return;
+
+	LL_DEBUGS("ParticleEditor") << "clearing particles from " << mObject->getID() << LL_ENDL;
+
+	LLViewerPartSim::getInstance()->clearParticlesByOwnerID(mObject->getID());
+}
+
+void LLFloaterParticleEditor::updateParticles()
+{
+	if (!mObject)
+		return;
+
+	clearParticles();
+	LLPointer<LLViewerPartSourceScript> pss = LLViewerPartSourceScript::createPSS(mObject, mParticles);
+
+	pss->setOwnerUUID(mObject->getID());
+	pss->setImage(mTexture);
+
+	LLViewerPartSim::getInstance()->addPartSource(pss);
+}
+
+void LLFloaterParticleEditor::setObject(LLViewerObject* objectp)
+{
+	if (objectp)
+	{
+		mObject = objectp;
+
+		LL_DEBUGS("ParticleEditor") << "adding particles to " << mObject->getID() << LL_ENDL;
+
+		updateParticles();
+	}
+}
+
+void LLFloaterParticleEditor::onParameterChange()
+{
+	mParticles.mPattern = sParticlePatterns.at(mPatternTypeCombo->getSelectedValue()).flag;
+	mParticles.mPartImageID = mTexturePicker->getImageAssetID();
+
+	// remember the selected texture here to give updateParticles() a UUID to work with
+	mTexture = LLViewerTextureManager::getFetchedTexture(mTexturePicker->getImageAssetID());
+
+	if (mTexture->getID() == IMG_DEFAULT || mTexture->getID().isNull())
+	{
+		mTexture = mDefaultParticleTexture;
+	}
+
+	// limit burst rate to 0.01 to avoid internal freeze, script still gets the real value
+	mParticles.mBurstRate = llmax<float>(0.01f, mBurstRateCtrl->getValue().asReal());
+	mParticles.mBurstPartCount = mBurstCountCtrl->getValue().asInteger();
+	mParticles.mBurstRadius = mBurstRadiusCtrl->getValue().asReal();
+	mParticles.mInnerAngle = mAngleBeginCtrl->getValue().asReal();
+	mParticles.mOuterAngle = mAngleEndCtrl->getValue().asReal();
+	mParticles.mBurstSpeedMin = mBurstSpeedMinCtrl->getValue().asReal();
+	mParticles.mBurstSpeedMax = mBurstSpeedMaxCtrl->getValue().asReal();
+	mParticles.mPartData.setStartAlpha(mStartAlphaCtrl->getValue().asReal());
+	mParticles.mPartData.setEndAlpha(mEndAlphaCtrl->getValue().asReal());
+	mParticles.mPartData.setStartScale(mScaleStartXCtrl->getValue().asReal(),
+									   mScaleStartYCtrl->getValue().asReal());
+	mParticles.mPartData.setEndScale(mScaleEndXCtrl->getValue().asReal(),
+									 mScaleEndYCtrl->getValue().asReal());
+	mParticles.mMaxAge = mSourceMaxAgeCtrl->getValue().asReal();
+	mParticles.mPartData.setMaxAge(mParticlesMaxAgeCtrl->getValue().asReal());
+
+	mParticles.mPartData.mStartGlow = mStartGlowCtrl->getValue().asReal();
+	mParticles.mPartData.mEndGlow = mEndGlowCtrl->getValue().asReal();
+
+	mParticles.mPartData.mBlendFuncSource = sParticleBlends.at(mBlendFuncSrcCombo->getSelectedValue()).flag;
+	mParticles.mPartData.mBlendFuncDest = sParticleBlends.at(mBlendFuncDestCombo->getSelectedValue()).flag;
+
+	U32 flags = 0;
+	if (mBounceCheckBox->getValue().asBoolean())			flags |= LLPartData::LL_PART_BOUNCE_MASK;
+	if (mEmissiveCheckBox->getValue().asBoolean())			flags |= LLPartData::LL_PART_EMISSIVE_MASK;
+	if (mFollowSourceCheckBox->getValue().asBoolean())		flags |= LLPartData::LL_PART_FOLLOW_SRC_MASK;
+	if (mFollowVelocityCheckBox->getValue().asBoolean())	flags |= LLPartData::LL_PART_FOLLOW_VELOCITY_MASK;
+	if (mInterpolateColorCheckBox->getValue().asBoolean())	flags |= LLPartData::LL_PART_INTERP_COLOR_MASK;
+	if (mInterpolateScaleCheckBox->getValue().asBoolean())	flags |= LLPartData::LL_PART_INTERP_SCALE_MASK;
+	if (mTargetPositionCheckBox->getValue().asBoolean())	flags |= LLPartData::LL_PART_TARGET_POS_MASK;
+	if (mTargetLinearCheckBox->getValue().asBoolean())		flags |= LLPartData::LL_PART_TARGET_LINEAR_MASK;
+	if (mWindCheckBox->getValue().asBoolean())				flags |= LLPartData::LL_PART_WIND_MASK;
+	if (mRibbonCheckBox->getValue().asBoolean())			flags |= LLPartData::LL_PART_RIBBON_MASK;
+	mParticles.mPartData.setFlags(flags);
+
+	mParticles.mTargetUUID = mTargetKeyInput->getValue().asUUID();
+
+	mParticles.mPartAccel = LLVector3(mAcellerationXCtrl->getValue().asReal(),
+									  mAcellerationYCtrl->getValue().asReal(),
+									  mAcellerationZCtrl->getValue().asReal());
+	mParticles.mAngularVelocity = LLVector3(mOmegaXCtrl->getValue().asReal(),
+											mOmegaYCtrl->getValue().asReal(),
+											mOmegaZCtrl->getValue().asReal());
+
+	LLColor4 color = mStartColorSelector->get();
+	mParticles.mPartData.setStartColor(LLVector3(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE]));
+	color = mEndColorSelector->get();
+	mParticles.mPartData.setEndColor(LLVector3(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE]));
+
+	updateUI();
+	updateParticles();
+}
+
+void LLFloaterParticleEditor::updateUI()
+{
+	U8 pattern = sParticlePatterns.at(mPatternTypeCombo->getValue()).flag;
+	BOOL drop_pattern = (pattern == LLPartSysData::LL_PART_SRC_PATTERN_DROP);
+	BOOL explode_pattern = (pattern == LLPartSysData::LL_PART_SRC_PATTERN_EXPLODE);
+	BOOL target_linear = mTargetLinearCheckBox->getValue();
+	BOOL interpolate_color = mInterpolateColorCheckBox->getValue();
+	BOOL interpolate_scale = mInterpolateScaleCheckBox->getValue();
+	BOOL target_enabled = target_linear | (mTargetPositionCheckBox->getValue().asBoolean() ? TRUE : FALSE);
+
+	mBurstRadiusCtrl->setEnabled(!(target_linear | (mFollowSourceCheckBox->getValue().asBoolean() ? TRUE : FALSE) | drop_pattern));
+	mBurstSpeedMinCtrl->setEnabled(!(target_linear | drop_pattern));
+	mBurstSpeedMaxCtrl->setEnabled(!(target_linear | drop_pattern));
+
+	// disabling a color swatch does nothing visually, so we also set alpha
+	LLColor4 end_color = mEndColorSelector->get();
+	end_color.setAlpha(interpolate_color ? 1.0f : 0.0f);
+
+	mEndAlphaCtrl->setEnabled(interpolate_color);
+	mEndColorSelector->set(end_color);
+	mEndColorSelector->setEnabled(interpolate_color);
+
+	mScaleEndXCtrl->setEnabled(interpolate_scale);
+	mScaleEndYCtrl->setEnabled(interpolate_scale);
+
+	mTargetPositionCheckBox->setEnabled(!target_linear);
+	mTargetKeyInput->setEnabled(target_enabled);
+	mPickTargetButton->setEnabled(target_enabled);
+	mClearTargetButton->setEnabled(target_enabled);
+
+	mAcellerationXCtrl->setEnabled(!target_linear);
+	mAcellerationYCtrl->setEnabled(!target_linear);
+	mAcellerationZCtrl->setEnabled(!target_linear);
+
+	mOmegaXCtrl->setEnabled(!target_linear);
+	mOmegaYCtrl->setEnabled(!target_linear);
+	mOmegaZCtrl->setEnabled(!target_linear);
+
+	mAngleBeginCtrl->setEnabled(!(explode_pattern | drop_pattern));
+	mAngleEndCtrl->setEnabled(!(explode_pattern | drop_pattern));
+}
+
+void LLFloaterParticleEditor::onClickClearTarget()
+{
+	mTargetKeyInput->clear();
+	onParameterChange();
+}
+
+void LLFloaterParticleEditor::onClickTargetPicker()
+{
+	mPickTargetButton->setToggleState(TRUE);
+	mPickTargetButton->setEnabled(FALSE);
+	startPicking(this);
+}
+
+// static
+void LLFloaterParticleEditor::startPicking(void* userdata)
+{
+	LLFloaterParticleEditor* self = static_cast<LLFloaterParticleEditor*>(userdata);
+	LLToolObjPicker::getInstance()->setExitCallback(LLFloaterParticleEditor::onTargetPicked, self);
+	LLToolMgr::getInstance()->setTransientTool(LLToolObjPicker::getInstance());
+}
+
+// static
+void LLFloaterParticleEditor::onTargetPicked(void* userdata)
+{
+	LLFloaterParticleEditor* self = static_cast<LLFloaterParticleEditor*>(userdata);
+
+	const LLUUID& picked = LLToolObjPicker::getInstance()->getObjectID();
+
+	LLToolMgr::getInstance()->clearTransientTool();
+
+	self->mPickTargetButton->setEnabled(TRUE);
+	self->mPickTargetButton->setToggleState(FALSE);
+
+	if (picked.notNull())
+	{
+		self->mTargetKeyInput->setValue(picked.asString());
+		self->onParameterChange();
+	}
+}
+
+std::string LLFloaterParticleEditor::lslVector(F32 x, F32 y, F32 z)
+{
+	return llformat("<%f,%f,%f>", x, y, z);
+}
+
+std::string LLFloaterParticleEditor::lslColor(const LLColor4& color)
+{
+	return lslVector(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE]);
+}
+
+std::string LLFloaterParticleEditor::createScript()
+{
+	std::string script(
+"\
+default\n\
+{\n\
+    state_entry()\n\
+    {\n\
+        llParticleSystem(\n\
+        [\n\
+            PSYS_SRC_PATTERN,[PATTERN],\n\
+            PSYS_SRC_BURST_RADIUS,[BURST_RADIUS],\n\
+            PSYS_SRC_ANGLE_BEGIN,[ANGLE_BEGIN],\n\
+            PSYS_SRC_ANGLE_END,[ANGLE_END],\n\
+            PSYS_SRC_TARGET_KEY,[TARGET_KEY],\n\
+            PSYS_PART_START_COLOR,[START_COLOR],\n\
+            PSYS_PART_END_COLOR,[END_COLOR],\n\
+            PSYS_PART_START_ALPHA,[START_ALPHA],\n\
+            PSYS_PART_END_ALPHA,[END_ALPHA],\n\
+            PSYS_PART_START_GLOW,[START_GLOW],\n\
+            PSYS_PART_END_GLOW,[END_GLOW],\n\
+            PSYS_PART_BLEND_FUNC_SOURCE,[BLEND_FUNC_SOURCE],\n\
+            PSYS_PART_BLEND_FUNC_DEST,[BLEND_FUNC_DEST],\n\
+            PSYS_PART_START_SCALE,[START_SCALE],\n\
+            PSYS_PART_END_SCALE,[END_SCALE],\n\
+            PSYS_SRC_TEXTURE,\"[TEXTURE]\",\n\
+            PSYS_SRC_MAX_AGE,[SOURCE_MAX_AGE],\n\
+            PSYS_PART_MAX_AGE,[PART_MAX_AGE],\n\
+            PSYS_SRC_BURST_RATE,[BURST_RATE],\n\
+            PSYS_SRC_BURST_PART_COUNT,[BURST_COUNT],\n\
+            PSYS_SRC_ACCEL,[ACCELERATION],\n\
+            PSYS_SRC_OMEGA,[OMEGA],\n\
+            PSYS_SRC_BURST_SPEED_MIN,[BURST_SPEED_MIN],\n\
+            PSYS_SRC_BURST_SPEED_MAX,[BURST_SPEED_MAX],\n\
+            PSYS_PART_FLAGS,\n\
+                0[FLAGS]\n\
+        ]);\n\
+    }\n\
+}\n");
+
+	const LLUUID& targetKey = mTargetKeyInput->getValue().asUUID();
+	std::string keyString = "llGetKey()";
+
+	if (targetKey.notNull() && targetKey != mObject->getID())
+	{
+		keyString="(key) \"" + targetKey.asString() + "\"";
+	}
+
+	LLUUID textureKey = mTexture->getID();
+	std::string textureString;
+	if (textureKey.notNull() && textureKey != IMG_DEFAULT && textureKey != mDefaultParticleTexture->getID())
+	{
+		textureString = textureKey.asString();
+	}
+
+	LLStringUtil::replaceString(script,"[PATTERN]", sParticlePatterns.at(mPatternTypeCombo->getValue()).script_const);
+	LLStringUtil::replaceString(script,"[BURST_RADIUS]", mBurstRadiusCtrl->getValue().asString());
+	LLStringUtil::replaceString(script,"[ANGLE_BEGIN]", mAngleBeginCtrl->getValue().asString());
+	LLStringUtil::replaceString(script,"[ANGLE_END]", mAngleEndCtrl->getValue().asString());
+	LLStringUtil::replaceString(script,"[TARGET_KEY]", keyString);
+	LLStringUtil::replaceString(script,"[START_COLOR]", lslColor(mStartColorSelector->get()));
+	LLStringUtil::replaceString(script,"[END_COLOR]", lslColor(mEndColorSelector->get()));
+	LLStringUtil::replaceString(script,"[START_ALPHA]", mStartAlphaCtrl->getValue().asString());
+	LLStringUtil::replaceString(script,"[END_ALPHA]", mEndAlphaCtrl->getValue().asString());
+	LLStringUtil::replaceString(script,"[START_GLOW]", mStartGlowCtrl->getValue().asString());
+	LLStringUtil::replaceString(script,"[END_GLOW]", mEndGlowCtrl->getValue().asString());
+	LLStringUtil::replaceString(script,"[START_SCALE]", lslVector(mScaleStartXCtrl->getValue().asReal(),
+																  mScaleStartYCtrl->getValue().asReal(),
+																  0.0f));
+	LLStringUtil::replaceString(script,"[END_SCALE]", lslVector(mScaleEndXCtrl->getValue().asReal(),
+																mScaleEndYCtrl->getValue().asReal(),
+																0.0f));
+	LLStringUtil::replaceString(script,"[TEXTURE]", textureString);
+	LLStringUtil::replaceString(script,"[SOURCE_MAX_AGE]", mSourceMaxAgeCtrl->getValue().asString());
+	LLStringUtil::replaceString(script,"[PART_MAX_AGE]", mParticlesMaxAgeCtrl->getValue().asString());
+	LLStringUtil::replaceString(script,"[BURST_RATE]", mBurstRateCtrl->getValue().asString());
+	LLStringUtil::replaceString(script,"[BURST_COUNT]", mBurstCountCtrl->getValue());
+	LLStringUtil::replaceString(script,"[ACCELERATION]", lslVector(mAcellerationXCtrl->getValue().asReal(),
+																   mAcellerationYCtrl->getValue().asReal(),
+																   mAcellerationZCtrl->getValue().asReal()));
+	LLStringUtil::replaceString(script,"[OMEGA]", lslVector(mOmegaXCtrl->getValue().asReal(),
+															mOmegaYCtrl->getValue().asReal(),
+															mOmegaZCtrl->getValue().asReal()));
+	LLStringUtil::replaceString(script,"[BURST_SPEED_MIN]", mBurstSpeedMinCtrl->getValue().asString());
+	LLStringUtil::replaceString(script,"[BURST_SPEED_MAX]", mBurstSpeedMaxCtrl->getValue().asString());
+	LLStringUtil::replaceString(script,"[BLEND_FUNC_SOURCE]", sParticleBlends.at(mBlendFuncSrcCombo->getValue().asString()).script_const);
+	LLStringUtil::replaceString(script,"[BLEND_FUNC_DEST]", sParticleBlends.at(mBlendFuncDestCombo->getValue().asString()).script_const);
+
+	std::string delimiter = " |\n                ";
+	std::string flagsString;
+
+	if (mBounceCheckBox->getValue())
+		flagsString += delimiter + "PSYS_PART_BOUNCE_MASK";
+	if (mEmissiveCheckBox->getValue())
+		flagsString += delimiter + "PSYS_PART_EMISSIVE_MASK";
+	if (mFollowSourceCheckBox->getValue())
+		flagsString += delimiter + "PSYS_PART_FOLLOW_SRC_MASK";
+	if (mFollowVelocityCheckBox->getValue())
+		flagsString += delimiter + "PSYS_PART_FOLLOW_VELOCITY_MASK";
+	if (mInterpolateColorCheckBox->getValue())
+		flagsString += delimiter + "PSYS_PART_INTERP_COLOR_MASK";
+	if (mInterpolateScaleCheckBox->getValue())
+		flagsString += delimiter + "PSYS_PART_INTERP_SCALE_MASK";
+	if (mTargetLinearCheckBox->getValue())
+		flagsString += delimiter + "PSYS_PART_TARGET_LINEAR_MASK";
+	if (mTargetPositionCheckBox->getValue())
+		flagsString += delimiter + "PSYS_PART_TARGET_POS_MASK";
+	if (mWindCheckBox->getValue())
+		flagsString += delimiter + "PSYS_PART_WIND_MASK";
+	if (mRibbonCheckBox->getValue())
+		flagsString += delimiter + "PSYS_PART_RIBBON_MASK";
+
+	LLStringUtil::replaceString(script, "[FLAGS]", flagsString);
+	LL_DEBUGS("ParticleEditor") << "\n" << script << LL_ENDL;
+
+	return script;
+}
+
+void LLFloaterParticleEditor::onClickCopy()
+{
+	const std::string& script = createScript();
+	if (!script.empty())
+	{
+		getWindow()->copyTextToClipboard(utf8str_to_wstring(script));
+		LLNotificationsUtil::add("ParticleScriptCopiedToClipboard");
+	}
+}
+
+void LLFloaterParticleEditor::onClickInject()
+{
+	const LLUUID& categoryID = gInventory.findCategoryUUIDForType(LLFolderType::FT_LSL_TEXT);
+
+	// if no valid folder found bail out and complain
+	if (categoryID.isNull())
+	{
+		LLNotificationsUtil::add("ParticleScriptFindFolderFailed");
+		return;
+	}
+
+	// setup permissions
+	LLPermissions perm;
+	perm.init(gAgentID, gAgentID, LLUUID::null, LLUUID::null);
+	perm.initMasks(PERM_ALL, PERM_ALL, PERM_ALL, PERM_ALL, PERM_ALL);
+
+	// create new script inventory item and wait for it to come back (callback)
+	LLPointer<LLInventoryCallback> callback = new LLParticleScriptCreationCallback(this);
+	create_inventory_item(
+		gAgentID,
+		gAgentSessionID,
+		categoryID,
+		LLTransactionID::tnull,
+		PARTICLE_SCRIPT_NAME,
+		LLStringUtil::null,
+		LLAssetType::AT_LSL_TEXT,
+		LLInventoryType::IT_LSL,
+		NOT_WEARABLE,
+		perm.getMaskNextOwner(),
+		callback);
+
+	setCanClose(FALSE);
+}
+
+void LLFloaterParticleEditor::callbackReturned(const LLUUID& inventoryItemID)
+{
+	setCanClose(TRUE);
+
+	if (inventoryItemID.isNull())
+	{
+		LLNotificationsUtil::add("ParticleScriptCreationFailed");
+		return;
+	}
+
+	mParticleScriptInventoryItem = gInventory.getItem(inventoryItemID);
+	if (!mParticleScriptInventoryItem) 
+	{
+		LLNotificationsUtil::add("ParticleScriptNotFound");
+		return;
+	}
+	gInventory.updateItem(mParticleScriptInventoryItem);
+	gInventory.notifyObservers();
+
+	//caps import 
+	const std::string& url = gAgent.getRegion()->getCapability("UpdateScriptAgent");
+
+	if (!url.empty())
+	{
+		const std::string& script = createScript();
+
+		const std::string& temp_file_path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "particle_script.lsltxt"));
+
+		std::ofstream temp_file;
+
+		temp_file.open(temp_file_path.c_str());
+		if (!temp_file.is_open())
+		{
+			LLNotificationsUtil::add("ParticleScriptCreateTempFileFailed");
+			return;
+		}
+
+		temp_file << script.c_str();
+		temp_file.close();
+
+		LLSD body;
+		body["task_id"] = mObject->getID();	// probably has no effect
+		body["item_id"] = inventoryItemID;
+		body["target"] = "mono";
+		body["is_script_running"] = true;
+
+		// responder will alert us when the job is done
+		LLHTTPClient::post(url, body, new LLParticleScriptUploadResponder(body, temp_file_path, LLAssetType::AT_LSL_TEXT, this));
+
+		//mMainPanel->setEnabled(FALSE);
+		setCanClose(FALSE);
+	}
+	else
+	{
+		LLNotificationsUtil::add("ParticleScriptCapsFailed");
+		return;
+	}
+}
+
+void LLFloaterParticleEditor::scriptInjectReturned(const LLSD& content)
+{
+	setCanClose(TRUE);
+
+	// play it safe, because some time may have passed
+	LLViewerObject* object = gObjectList.findObject(mObject->getID());
+	if (!object)
+	{
+		LL_DEBUGS("ParticleEditor") << "Can't find " << mObject->getID().asString() << " anymore!" << LL_ENDL;
+		//mMainPanel->setEnabled(TRUE);
+		return;
+	}
+
+	mObject->saveScript(mParticleScriptInventoryItem, TRUE, FALSE);
+	LLNotificationsUtil::add("ParticleScriptInjected");
+
+	delete this;
+}
+
+// ---------------------------------- Callbacks ----------------------------------
+
+LLFloaterParticleEditor::LLParticleScriptCreationCallback::
+LLParticleScriptCreationCallback(LLFloaterParticleEditor* editor)
+:	mEditor(editor)
+{
+}
+
+void LLFloaterParticleEditor::LLParticleScriptCreationCallback::fire(const LLUUID& inventoryItem)
+{
+	if (!gDisconnected && !LLAppViewer::instance()->quitRequested() && mEditor)
+	{
+		mEditor->callbackReturned(inventoryItem);
+	}
+}
+
+// ---------------------------------- Responders ----------------------------------
+
+LLFloaterParticleEditor::LLParticleScriptUploadResponder::
+	LLParticleScriptUploadResponder(const LLSD& post_data,
+									const std::string& file_name,
+									LLAssetType::EType asset_type,
+									LLFloaterParticleEditor* editor)
+:	LLUpdateAgentInventoryResponder(post_data, file_name, asset_type)
+,	mEditor(editor)
+{}
+
+void LLFloaterParticleEditor::LLParticleScriptUploadResponder::uploadComplete(const LLSD& content)
+{
+	LLUpdateAgentInventoryResponder::uploadComplete(content);
+	if (!gDisconnected && !LLAppViewer::instance()->quitRequested() && mEditor)
+	{
+		mEditor->scriptInjectReturned(content);
+	}
+}
diff --git a/indra/newview/llfloaterparticleeditor.h b/indra/newview/llfloaterparticleeditor.h
new file mode 100644
index 0000000000000000000000000000000000000000..242c87302ce453b721e03c7a81315e5ae1d9b77b
--- /dev/null
+++ b/indra/newview/llfloaterparticleeditor.h
@@ -0,0 +1,161 @@
+/** 
+ * @file llfloaterparticleeditor.h
+ * @brief Particle Editor
+ *
+ * Copyright (C) 2011, Zi Ree @ Second Life
+ * Copyright (C) 2015, Cinder Roxley <cinder@sdf.org>
+ * 
+ * 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
+ */
+
+#ifndef LL_FLOATERPARTICLEEDITOR_H
+#define LL_FLOATERPARTICLEEDITOR_H
+
+#include "llfloater.h"
+#include "llpartdata.h"
+#include "llviewerinventory.h"
+#include "llassetuploadresponders.h"
+
+class LLButton;
+class LLCheckBoxCtrl;
+class LLColorSwatchCtrl;
+class LLComboBox;
+class LLTextureCtrl;
+class LLUICtrl;
+class LLViewerObject;
+class LLViewerTexture;
+
+const std::string PARTICLE_SCRIPT_NAME = "New Particle Script";
+
+class LLFloaterParticleEditor : public LLFloater
+{
+public:
+	LLFloaterParticleEditor(const LLSD& key);
+	/* virtual */ ~LLFloaterParticleEditor();
+
+	/* virtual */ BOOL postBuild();
+
+	void setObject(LLViewerObject* objectp);
+
+private:
+	void clearParticles();
+	void updateParticles();
+	void updateUI();
+
+	std::string createScript();
+
+	void onParameterChange();
+	void onClickCopy();
+	void onClickInject();
+
+	void onClickClearTarget();
+	void onClickTargetPicker();
+	static void startPicking(void* userdata);
+	static void onTargetPicked(void* userdata);
+
+	void callbackReturned(const LLUUID& inv_item);
+	void scriptInjectReturned(const LLSD& content);
+
+	std::string lslVector(F32 x, F32 y, F32 z);
+	std::string lslColor(const LLColor4& color);
+
+	LLViewerObject* mObject;
+	LLViewerTexture* mTexture;
+	LLViewerInventoryItem* mParticleScriptInventoryItem;
+
+	LLViewerTexture* mDefaultParticleTexture;
+	
+	LLPartSysData mParticles;
+
+	LLComboBox* mPatternTypeCombo;
+	LLTextureCtrl* mTexturePicker;
+
+	LLUICtrl* mBurstRateCtrl;
+	LLUICtrl* mBurstCountCtrl;
+	LLUICtrl* mBurstRadiusCtrl;
+	LLUICtrl* mAngleBeginCtrl;
+	LLUICtrl* mAngleEndCtrl;
+	LLUICtrl* mBurstSpeedMinCtrl;
+	LLUICtrl* mBurstSpeedMaxCtrl;
+	LLUICtrl* mStartAlphaCtrl;
+	LLUICtrl* mEndAlphaCtrl;
+	LLUICtrl* mScaleStartXCtrl;
+	LLUICtrl* mScaleStartYCtrl;
+	LLUICtrl* mScaleEndXCtrl;
+	LLUICtrl* mScaleEndYCtrl;
+	LLUICtrl* mSourceMaxAgeCtrl;
+	LLUICtrl* mParticlesMaxAgeCtrl;
+	LLUICtrl* mStartGlowCtrl;
+	LLUICtrl* mEndGlowCtrl;
+	
+	LLUICtrl* mAcellerationXCtrl;
+	LLUICtrl* mAcellerationYCtrl;
+	LLUICtrl* mAcellerationZCtrl;
+	
+	LLUICtrl* mOmegaXCtrl;
+	LLUICtrl* mOmegaYCtrl;
+	LLUICtrl* mOmegaZCtrl;
+
+	LLComboBox* mBlendFuncSrcCombo;
+	LLComboBox* mBlendFuncDestCombo;
+
+	LLCheckBoxCtrl* mBounceCheckBox;
+	LLCheckBoxCtrl* mEmissiveCheckBox;
+	LLCheckBoxCtrl* mFollowSourceCheckBox;
+	LLCheckBoxCtrl* mFollowVelocityCheckBox;
+	LLCheckBoxCtrl* mInterpolateColorCheckBox;
+	LLCheckBoxCtrl* mInterpolateScaleCheckBox;
+	LLCheckBoxCtrl* mTargetPositionCheckBox;
+	LLCheckBoxCtrl* mTargetLinearCheckBox;
+	LLCheckBoxCtrl* mWindCheckBox;
+	LLCheckBoxCtrl* mRibbonCheckBox;
+
+	LLUICtrl* mTargetKeyInput;
+	LLButton* mClearTargetButton;
+	LLButton* mPickTargetButton;
+	LLButton* mCopyToLSLButton;
+	LLButton* mInjectScriptButton;
+
+	LLColorSwatchCtrl* mStartColorSelector;
+	LLColorSwatchCtrl* mEndColorSelector;
+	
+	class LLParticleScriptCreationCallback : public LLInventoryCallback
+	{
+	public:
+		LLParticleScriptCreationCallback(LLFloaterParticleEditor* editor);
+		void fire(const LLUUID& inventoryItem);
+		
+	protected:
+		~LLParticleScriptCreationCallback() {}
+		
+		LLFloaterParticleEditor* mEditor;
+	};
+	
+	class LLParticleScriptUploadResponder : public LLUpdateAgentInventoryResponder
+	{
+	public:
+		LLParticleScriptUploadResponder(const LLSD& post_data,
+										const std::string& file_name,
+										LLAssetType::EType asset_type,
+										LLFloaterParticleEditor* editor);
+		
+	protected:
+		void uploadComplete(const LLSD& content);
+		
+		LLFloaterParticleEditor* mEditor;
+	};
+};
+
+#endif // LL_FLOATERPARTICLEEDITOR_H
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index b6a736332faaa62095a4d961da05f3bb70b5320c..1d959dcf85001ed7f6ca95c7bce82b984394e3cc 100755
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -93,6 +93,7 @@
 #include "llfloaterobjectweights.h"
 #include "llfloateropenobject.h"
 #include "llfloateroutbox.h"
+#include "llfloaterparticleeditor.h"
 #include "llfloaterpathfindingcharacters.h"
 #include "llfloaterpathfindingconsole.h"
 #include "llfloaterpathfindinglinksets.h"
@@ -277,6 +278,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>);
 	LLFloaterPayUtil::registerFloater();
 
+	LLFloaterReg::add("particle_editor","floater_particle_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterParticleEditor>);
 	LLFloaterReg::add("pathfinding_characters", "floater_pathfinding_characters.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingCharacters>);
 	LLFloaterReg::add("pathfinding_linksets", "floater_pathfinding_linksets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingLinksets>);
 	LLFloaterReg::add("pathfinding_console", "floater_pathfinding_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingConsole>);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index e1295cd96577acf84f71b9ea5d90c1d63b3a50e5..ed52f5d2326bb3e11f5c8823e77a15f82e8e990d 100755
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -67,6 +67,7 @@
 #include "llfloaterimcontainer.h"
 #include "llfloaterland.h"
 #include "llfloaterimnearbychat.h"
+#include "llfloaterparticleeditor.h"
 #include "llfloaterpathfindingcharacters.h"
 #include "llfloaterpathfindinglinksets.h"
 #include "llfloaterpay.h"
@@ -3174,6 +3175,37 @@ class LLObjectMute : public view_listener_t
 };
 
 // <Alchemy>
+class LLEnableEditParticleSource : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		if (LLSelectMgr::instance().getSelection()->getObjectCount())
+		{
+			LLObjectSelection::valid_root_iterator iter = LLSelectMgr::instance().getSelection()->valid_root_begin();
+			LLSelectNode* node = *iter;
+			
+			if (node->mPermissions->getOwner() == gAgent.getID())
+				return true;
+		}
+		return false;
+	}
+};
+
+class LLEditParticleSource : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+		if (objectp)
+		{
+			LLFloaterParticleEditor* particleEditor = LLFloaterReg::showTypedInstance<LLFloaterParticleEditor>("particle_editor", LLSD(objectp->getID()), TAKE_FOCUS_YES);
+			if(particleEditor)
+				particleEditor->setObject(objectp);
+		}
+		return true;
+	}
+};
+
 class LLSyncAnimations : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
@@ -9208,6 +9240,8 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono");
 	view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints");
 	// <Alchemy>
+    view_listener_t::addMenu(new LLEditParticleSource(), "Object.EditParticles");
+    view_listener_t::addMenu(new LLEnableEditParticleSource(), "Object.EnableEditParticles");
 	view_listener_t::addMenu(new LLSyncAnimations(), "Tools.ResyncAnimations");
 	view_listener_t::addMenu(new ALMarkViewerEffectsDead(), "Tools.AllVEDead");
 	// </Alchemy>
diff --git a/indra/newview/skins/default/xui/en/floater_particle_editor.xml b/indra/newview/skins/default/xui/en/floater_particle_editor.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d6ec367c093c7d58961ce927ec19a3d10d8384a1
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_particle_editor.xml
@@ -0,0 +1,876 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_resize="true"
+ height="357"
+	min_height="359"
+	min_width="450"
+	name="particle_editor_floater"
+	save_rect="true"
+	save_visibility="false"
+	single_instance="false"
+	title="PARTICLE EDITOR"
+	width="450">
+  <layout_stack
+   follows="all"
+   animate="false"
+   top="0"
+   height="357"
+   left="0"
+   right="-1"
+   drag_handle_gap="0"
+   drag_handle_first_indent="1"
+   drag_handle_second_indent="1"
+   layout="topleft"
+   name="master_stack"
+   orientation="horizontal"
+   show_drag_handle="true">
+    <layout_panel
+     bg_alpha_color="DkGray2"
+     bg_opaque_color="DkGray2"
+     background_visible="true"
+     background_opaque="true"
+     name="layout_master"
+     follows="all"
+     layout="topleft"
+     auto_resize="false"
+     user_resize="false"
+     height="357"
+     width="280">
+      <accordion
+       left="0"
+       top="0"
+       single_expansion="false"
+       follows="all"
+       layout="topleft"
+       name="accordion_master"
+       height="357"
+       width="275">
+        <accordion_tab
+         expanded="true"
+         layout="topleft"
+         height="152"
+         name="burst_tab"
+         title="Burst/Age"
+         fit_panel="true">
+          <panel
+           follows="all"
+           height="152"
+           left="0"
+           name="burst_panel"
+           top="0"
+        	  right="-1">
+            <slider
+             follows="left|top"
+             decimal_digits="2"
+             initial_value="0.3"
+             increment="0.1"
+             name="burst_rate"
+             label="Rate:"
+             label_width="50"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="0"
+             height="16"
+             max_val="1000"
+             top="0">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="0"
+             initial_value="5"
+             increment="1"
+             name="burst_count"
+             label="Count:"
+             label_width="50"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="1"
+             height="16"
+             max_val="1000"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="0"
+             increment="0.001"
+             name="burst_radius"
+             label="Radius:"
+             label_width="50"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="0"
+             max_val="50"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="0.5"
+             increment="0.001"
+             name="burst_speed_max"
+             label="Speed Max:"
+             label_width="70"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="0"
+             max_val="100"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="0.5"
+             increment="0.001"
+             name="burst_speed_min"
+             label="Speed Min:"
+             label_width="70"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="0"
+             max_val="100"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="0"
+             increment="0.001"
+             name="source_max_age"
+             label="Source Max Age:"
+             label_width="100"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="0"
+             max_val="1000"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="5"
+             increment="0.001"
+             name="particle_max_age"
+             label="Particle Max Age:"
+             label_width="100"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="0"
+             max_val="30"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+          </panel>
+        </accordion_tab>
+        <accordion_tab
+         expanded="false"
+         layout="topleft"
+         height="140"
+         name="angle_tab"
+         title="Scale/Angle"
+         fit_panel="true">
+          <panel
+           follows="all"
+           height="140"
+           left="0"
+           name="angle_panel"
+           top="0"
+        	  width="313">
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="0.5"
+             increment="0.001"
+             name="scale_start_x"
+             label="Scale Start X:"
+             label_width="72"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="0.03125"
+             max_val="4"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="0.5"
+             increment="0.001"
+             name="scale_start_y"
+             label="Scale Start Y:"
+             label_width="72"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="0.03125"
+             max_val="4"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="0.5"
+             increment="0.001"
+             name="scale_end_x"
+             label="Scale End Y:"
+             label_width="70"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="0.03125"
+             max_val="4"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+              function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="0.5"
+             increment="0.001"
+             name="scale_end_y"
+             label="Scale End Y:"
+             label_width="70"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="0.03125"
+             max_val="4"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="0"
+             increment="0.001"
+             name="angle_begin"
+             label="Angle Begin:"
+             label_width="70"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="-3.14"
+             max_val="3.14"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="0"
+             increment="0.001"
+             name="angle_end"
+             label="Angle End:"
+             label_width="70"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="-3.14"
+             max_val="3.14"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+          </panel>
+        </accordion_tab>
+        <accordion_tab
+         expanded="false"
+         layout="topleft"
+         height="100"
+         name="alpha_tab"
+         title="Alpha/Glow"
+         fit_panel="true">
+          <panel
+           follows="all"
+           height="100"
+           left="0"
+           name="alpha_panel"
+           top="0"
+        	  width="313">
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="1"
+             increment="0.001"
+             name="start_alpha"
+             label="Start Alpha:"
+             label_width="70"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="0"
+             max_val="1"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="1"
+             increment="0.001"
+             name="end_alpha"
+             label="End Alpha:"
+             label_width="70"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="0"
+             max_val="1"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="0"
+             increment="0.001"
+             name="start_glow"
+             label="Start Glow:"
+             label_width="70"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="0"
+             max_val="1"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="3"
+             initial_value="0"
+             increment="0.001"
+             name="end_glow"
+             label="End Glow:"
+             label_width="70"
+             can_edit_text="true"
+             left="0"
+             width="275"
+             min_val="0"
+             max_val="1"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+          </panel>
+        </accordion_tab>
+        <accordion_tab
+         expanded="false"
+         layout="topleft"
+         height="100"
+         name="omega_tab"
+         title="Acelleration/Omega"
+         fit_panel="true">
+          <panel
+           follows="all"
+           height="100"
+           left="0"
+           name="omega_panel"
+           top="0"
+        	  width="313">
+            <text
+             name="Acceleration_Label"
+             follows="left|top"
+             height="16"
+             left="0"
+             top="0"
+             width="76">
+            Acceleration:
+            </text>
+            <slider
+             follows="left|top"
+             decimal_digits="2"
+             initial_value="0"
+             increment="0.01"
+             name="acceleration_x"
+             label="X:"
+             label_width="10"
+             can_edit_text="true"
+             left="0"
+             width="90"
+             min_val="-100"
+             max_val="100"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="2"
+             initial_value="0"
+             increment="0.01"
+             name="acceleration_y"
+             can_edit_text="true"
+             label="Y:"
+             label_width="10"
+             left_pad="2"
+             width="90"
+             min_val="-100"
+             max_val="100"
+             height="16"
+             top_delta="0">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="2"
+             initial_value="0"
+             increment="0.01"
+             name="acceleration_z"
+             can_edit_text="true"
+             label="Z:"
+             label_width="10"
+             left_pad="2"
+             width="90"
+             min_val="-100"
+             max_val="100"
+             height="16"
+             top_delta="0">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <text
+             name="Omega_Label"
+             follows="left|top"
+             height="16"
+             left="0"
+             top_pad="4"
+             width="76">
+            Omega:
+            </text>
+            <slider
+             follows="left|top"
+             decimal_digits="2"
+             initial_value="0"
+             increment="0.01"
+             name="omega_x"
+             label="X:"
+             label_width="10"
+             can_edit_text="true"
+             left="0"
+             width="90"
+             min_val="-100"
+             max_val="100"
+             height="16"
+             top_pad="2">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="2"
+             initial_value="0"
+             increment="0.01"
+             name="omega_y"
+             label="Y:"
+             label_width="10"
+             can_edit_text="true"
+             left_pad="2"
+             width="90"
+             min_val="-100"
+             max_val="100"
+             height="16"
+             top_delta="0">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+            <slider
+             follows="left|top"
+             decimal_digits="2"
+             initial_value="0"
+             increment="0.01"
+             name="omega_z"
+             label="Z:"
+             label_width="10"
+             can_edit_text="true"
+             left_pad="2"
+             width="90"
+             min_val="-100"
+             max_val="100"
+             height="16"
+             top_delta="0">
+              <slider.commit_callback
+               function="Particle.Edit" />
+            </slider>
+          </panel>
+        </accordion_tab>
+        <accordion_tab
+         expanded="true"
+         layout="topleft"
+         height="100"
+         name="color_tab"
+         title="Color/Texture"
+         fit_panel="true">
+          <panel
+           follows="all"
+           height="100"
+           left="0"
+           name="color_panel"
+           top="0"
+        	  width="313">
+            <texture_picker
+             follows="top|right"
+             height="70"
+             width="60"
+             left="50"
+             can_apply_immediately="true"
+             name="texture_picker"
+             label="Texture"
+             top="4">
+              <texture_picker.commit_callback
+               function="Particle.Edit" />
+            </texture_picker>
+            <color_swatch
+             follows="left|top"
+             height="70"
+             width="60"
+             label="Start Color"
+             left_delta="17"
+             can_apply_immediately="true"
+             name="start_color_selector"
+             top_delta="0">
+              <color_swatch.commit_callback
+               function="Particle.Edit" />
+            </color_swatch>
+            <color_swatch
+             follows="left|top"
+             height="70"
+             width="60"
+             label="End Color"
+             left_pad="3"
+             name="end_color_selector"
+             can_apply_immediately="true"
+             top_delta="0">
+              <color_swatch.commit_callback
+               function="Particle.Edit" />
+            </color_swatch>
+            <combo_box
+             name="blend_func_src_combo"
+             follows="left|top"
+            	height="22"
+            	left_pad="4"
+            	top_delta="0"
+            	width="74">
+              <combo_box.commit_callback
+               function="Particle.Edit" />
+             	<combo_box.item
+               label="Blend One"
+               name="blend_one"
+             		value="blend_one" />
+             	<combo_box.item
+             		label="Blend Zero"
+             		name="blend_zero"
+             		value="blend_zero" />
+             	<combo_box.item
+             		label="Blend Dest Color"
+             		name="blend_dest_color"
+             		value="blend_dest_color" />
+             	<combo_box.item
+             		label="Blend Src Color"
+             		name="blend_src_color"
+             		value="blend_src_color" />
+             	<combo_box.item
+             		label="Blend 1 - Dest Color"
+             		name="blend_one_minus_dest_color"
+             		value="blend_one_minus_dest_color" />
+             	<combo_box.item
+             		label="Blend 1 - Src Color"
+             		name="blend_one_minus_src_color"
+             		value="blend_one_minus_src_color" />
+             	<combo_box.item
+             		label="Blend Src Alpha"
+             		name="blend_src_alpha"
+             		value="blend_src_alpha" />
+             	<combo_box.item
+             		label="Blend 1 - Src Alpha"
+             		name="blend_one_minus_src_alpha"
+             		value="blend_one_minus_src_alpha" />
+            </combo_box>
+            <combo_box
+             name="blend_func_dest_combo"
+             follows="left|top"
+             height="22"
+             left_delta="0"
+             top_pad="4"
+             width="74">
+              <combo_box.commit_callback
+               function="Particle.Edit" />
+             	<combo_box.item
+             		label="Blend One"
+             		name="blend_one"
+             		value="blend_one" />
+             	<combo_box.item
+             		label="Blend Zero"
+             		name="blend_zero"
+             		value="blend_zero" />
+             	<combo_box.item
+             		label="Blend Dest Color"
+             		name="blend_dest_color"
+             		value="blend_dest_color" />
+             	<combo_box.item
+             		label="Blend Src Color"
+             		name="blend_src_color"
+             		value="blend_src_color" />
+             	<combo_box.item
+             		label="Blend 1 - Dest Color"
+             		name="blend_one_minus_dest_color"
+             		value="blend_one_minus_dest_color" />
+             	<combo_box.item
+             		label="Blend 1 - Src Color"
+             		name="blend_one_minus_src_color"
+             		value="blend_one_minus_src_color" />
+             	<combo_box.item
+             		label="Blend Src Alpha"
+             		name="blend_src_alpha"
+             		value="blend_src_alpha" />
+             	<combo_box.item
+             		label="Blend 1 - Src Alpha"
+             		name="blend_one_minus_src_alpha"
+             		value="blend_one_minus_src_alpha" />
+             </combo_box>
+            </panel>
+          </accordion_tab>
+        </accordion>
+      </layout_panel>
+      <layout_panel
+       layout="topleft"
+      	follows="all"
+      	height="258"
+      	left_pad="0"
+      	name="checkbox_panel"
+      	width="120">
+      <text
+       name="Pattern_Label"
+	      follows="left|top"
+      	height="16"
+      	left="0"
+      	top="0"
+      	width="100">
+      Pattern:
+      </text>
+      <combo_box
+      	follows="left|right|top"
+      	name="pattern_type_combo"
+      	top_pad="2"
+      	left_delta="0"
+       right="-2">
+        <combo_box.commit_callback
+         function="Particle.Edit" />
+        <combo_box.item
+         label="Explode"
+         name="explode"
+         value="explode" />
+        <combo_box.item
+         label="Angle"
+         name="angle"
+         value="angle" />
+       	<combo_box.item
+      		 label="Angle Cone"
+      	 	name="angle_cone"
+       		value="angle_cone" />
+       	<combo_box.item
+      		 label="Angle Cone Empty"
+      	 	name="angle_cone_empty"
+       		value="angle_cone_empty" />
+      	 <combo_box.item
+      		 label="Drop"
+      	 	name="drop"
+       		value="drop" />
+      </combo_box>
+      <check_box
+      	follows="left|top"
+      	height="16"
+      	name="bounce_checkbox"
+      	label="Bounce"
+      	left="0"
+      	top_pad="4"
+      	width="80">
+        <check_box.commit_callback
+         function="Particle.Edit" />
+      </check_box>
+      <check_box
+      	follows="left|top"
+      	height="16"
+      	name="emissive_checkbox"
+      	label="Emissive"
+      	top_pad="4"
+       left="0"
+      	width="80">
+        <check_box.commit_callback
+         function="Particle.Edit" />
+      </check_box>
+      <check_box
+      	follows="left|top"
+      	height="16"
+      	name="wind_checkbox"
+      	label="Wind"
+      	top_pad="4"
+       left="0"
+      	width="80">
+        <check_box.commit_callback
+         function="Particle.Edit" />
+      </check_box>
+      <check_box
+      	follows="left|top"
+      	height="16"
+      	name="ribbon_checkbox"
+      	label="Ribbon"
+      	top_pad="4"
+       left="0"
+      	width="80">
+        <check_box.commit_callback
+         function="Particle.Edit" />
+      </check_box>
+      <check_box
+      	follows="left|top"
+      	height="16"
+      	name="follow_source_checkbox"
+      	label="Follow Source"
+      	top_pad="4"
+       left="0"
+      	width="120">
+        <check_box.commit_callback
+         function="Particle.Edit" />
+      </check_box>
+      <check_box
+      	follows="left|top"
+      	height="16"
+      	name="follow_velocity_checkbox"
+      	label="Follow Velocity"
+      	top_pad="4"
+      	width="120">
+        <check_box.commit_callback
+         function="Particle.Edit" />
+      </check_box>
+      <check_box
+      	follows="left|top"
+      	height="16"
+      	name="interpolate_color_checkbox"
+      	label="Interpolate Color"
+      	top_pad="4"
+      	width="120">
+        <check_box.commit_callback
+         function="Particle.Edit" />
+      </check_box>
+      <check_box
+    	  follows="left|top"
+      	height="16"
+      	name="interpolate_scale_checkbox"
+      	label="Interpolate Scale"
+      	top_pad="4"
+      	width="120">
+        <check_box.commit_callback
+         function="Particle.Edit" />
+      </check_box>
+      <check_box
+      	follows="left|top"
+      	height="16"
+      	name="target_position_checkbox"
+      	label="Target Position"
+      	top_pad="4"
+      	width="120">
+        <check_box.commit_callback
+         function="Particle.Edit" />
+      </check_box>
+      <check_box
+      	follows="left|top"
+      	height="16"
+      	name="target_linear_checkbox"
+      	label="Target Linear"
+      	top_pad="4"
+      	width="120">
+        <check_box.commit_callback
+         function="Particle.Edit" />
+      </check_box>
+      <line_editor
+       follows="left|right|top"
+       left="0"
+       name="target_key_input"
+       height="20"
+       right="-48">
+        <line_editor.commit_callback
+         function="Particle.Edit" />
+      </line_editor>
+      <button
+       follows="right|top"
+       image_overlay="StopReload_Over"
+       left_pad="4"
+       name="clear_target_button"
+       tool_tip="Clear target object or avatar"
+       width="20"
+       height="20" />
+      <button
+       follows="right|top"
+       image_overlay="Inv_Object"
+       left_pad="2"
+       name="pick_target_button"
+       tool_tip="Click here to select the particle target object or avatar."
+       width="20"
+       height="20" />
+      <button
+       follows="left|top"
+      	height="24"
+      	name="copy_button"
+      	label="Copy"
+      	tool_tip="Copies the particle system's parameter as LSL script to the clipboard."
+      	top_pad="7"
+       left="0"
+      	width="80" />
+      <button
+      	follows="left|top"
+      	height="24"
+      	name="inject_button"
+      	label="Inject"
+      	tool_tip="Inject this particle system into the selected object."
+      	left_pad="4"
+       width="80" />
+    </layout_panel>
+  </layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_object.xml b/indra/newview/skins/default/xui/en/menu_object.xml
index 6eff009203be3174f4d00c04b2401423a156d9e7..858db3eb14838f4d1ad6d497490b45ab90fed376 100755
--- a/indra/newview/skins/default/xui/en/menu_object.xml
+++ b/indra/newview/skins/default/xui/en/menu_object.xml
@@ -29,6 +29,14 @@
     <menu_item_call.on_enable
         function="EnableEdit"/>
   </menu_item_call>
+  <menu_item_call
+      label="Edit Particles"
+      name="Menu Object Edit Particles">
+    <menu_item_call.on_click
+        function="Object.EditParticles" />
+    <menu_item_call.on_enable
+        function="Object.EnableEditParticles" />
+  </menu_item_call>
   <menu_item_call
       enabled="false"
       label="Open"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 2b68b6524d329866c720ac7fa6b027f75b9b45d6..63a05a607a144bc41e9862f5b53a2317089cf5d3 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1049,6 +1049,14 @@
 			<menu_item_call.on_enable
                function="Tools.EnableTakeCopy" />
           </menu_item_call>
+          <menu_item_call
+             label="Edit Particles"
+             name="Menu Object Edit Particles">
+            <menu_item_call.on_click
+               function="Object.EditParticles" />
+            <menu_item_call.on_enable
+               function="Object.EnableEditParticles" />
+		  </menu_item_call>
           <menu_item_call
 			 label="Save Back to Object Contents"
 			 name="Save Object Back to Object Contents">
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index b1e645a62e548aa23eaabecefe10866d6b838024..84e6c6e1ecd277e9ed8062c2371af8f0d9b67e9c 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -10749,6 +10749,68 @@ the region &quot;[REGION]&quot;?
     Auto-accepted [ITEM] from [NAME] and placed in inventory.
   </notification>
 
+  <notification
+   icon="alertmodal.tga"
+   name="ParticleScriptFindFolderFailed"
+   type="alertmodal">
+Could not find a folder for the new script in inventory.
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="ParticleScriptCreationFailed"
+   type="alertmodal">
+Could not create new script for this particle system.
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="ParticleScriptNotFound"
+   type="alertmodal">
+Could not find the newly created script for this particle system.
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="ParticleScriptCreateTempFileFailed"
+   type="alertmodal">
+Could not create temporary file for script upload.
+   <form name="form">
+      <ignore name="ignore"
+       text="A particle script was copied to my clipboard"/>
+    </form>
+  </notification>
+
+  <notification
+   icon="notify.tga"
+   name="ParticleScriptInjected"
+   type="alertmodal">
+Particle script was injected successfully.
+   <form name="form">
+      <ignore name="ignore"
+       text="A particle script was injected to an object."/>
+    </form>
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="ParticleScriptCapsFailed"
+   type="alertmodal">
+Failed to inject script into object. Request for capabilities returned an empty address.
+  </notification>
+
+  <notification
+   icon="notify.tga"
+   name="ParticleScriptCopiedToClipboard"
+   type="alertmodal">
+The LSL script to create this particle system has been copied to your clipboard. You can now paste it into a new script to use it.
+   <form name="form">
+      <ignore name="ignore"
+       text="A particle script was copied to my clipboard"/>
+    </form>
+  </notification>
+
+
   <notification
     icon="alertmodal.tga"
     name="RevokedMapRights"