diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/ILayoutRoomListener.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/ILayoutRoomListener.java
new file mode 100755
index 0000000000000000000000000000000000000000..526c9eb8aad7d4151a2c43d15f220d8c800095e6
--- /dev/null
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/ILayoutRoomListener.java
@@ -0,0 +1,29 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.conference.service.layout;
+
+import java.util.List;
+
+public interface ILayoutRoomListener {
+	public String getName();
+	public void updateLayout(List<Object> args);
+//	public void lockLayout();
+//	public void unlockLayout();
+}
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutApplication.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutApplication.java
new file mode 100755
index 0000000000000000000000000000000000000000..13fbcbfdfae11ca2134eabc011b55e9cd97e9d2b
--- /dev/null
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutApplication.java
@@ -0,0 +1,75 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.conference.service.layout;
+
+import java.util.List;
+
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+
+public class LayoutApplication {
+
+	private static Logger log = Red5LoggerFactory.getLogger( LayoutApplication.class, "bigbluebutton" );	
+		
+	private LayoutRoomsManager roomsManager;
+	public LayoutHandler handler;
+	
+	public boolean createRoom(String name) {
+		roomsManager.addRoom(new LayoutRoom(name));
+		return true;
+	}
+	
+	public boolean destroyRoom(String name) {
+		if (roomsManager.hasRoom(name)) {
+			roomsManager.removeRoom(name);
+		}
+		return true;
+	}
+	
+	public boolean hasRoom(String name) {
+		return roomsManager.hasRoom(name);
+	}
+	
+	public boolean addRoomListener(String room, ILayoutRoomListener listener) {
+		if (roomsManager.hasRoom(room)){
+			roomsManager.addRoomListener(room, listener);
+			return true;
+		}
+		log.warn("Adding listener to a non-existant room " + room);
+		return false;
+	}
+	
+	public void setRoomsManager(LayoutRoomsManager r) {
+		log.debug("Setting room manager");
+		roomsManager = r;
+	}
+
+	public void lockLayout(String room, int userId, String layout) {
+		roomsManager.lockLayout(room, userId, layout);
+	}
+
+	public void unlockLayout(String room) {
+		roomsManager.unlockLayout(room);
+	}
+
+	public List<Object> currentLayout(String roomName) {
+		return roomsManager.currentLayout(roomName);
+	}
+}
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutHandler.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..14ea32ee214cff33d790b3e6a6858d9aa5cbbb8d
--- /dev/null
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutHandler.java
@@ -0,0 +1,130 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.conference.service.layout;
+
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.adapter.ApplicationAdapter;
+import org.red5.server.adapter.IApplication;
+import org.red5.server.api.IClient;
+import org.red5.server.api.IConnection;
+import org.red5.server.api.IScope;
+import org.red5.server.api.so.ISharedObject;
+import org.slf4j.Logger;
+
+public class LayoutHandler extends ApplicationAdapter implements IApplication {
+	private static Logger log = Red5LoggerFactory.getLogger( LayoutHandler.class, "bigbluebutton" );
+
+	private static final String APP = "LAYOUT";
+	private static final String LAYOUT_SO = "layoutSO";   
+
+	private LayoutApplication layoutApplication;
+
+	@Override
+	public boolean appConnect(IConnection conn, Object[] params) {
+		log.debug(APP + ":appConnect");
+		return true;
+	}
+
+	@Override
+	public void appDisconnect(IConnection conn) {
+		log.debug( APP + ":appDisconnect");
+	}
+
+	@Override
+	public boolean appJoin(IClient client, IScope scope) {
+		log.debug( APP + ":appJoin " + scope.getName());
+		return true;
+	}
+
+	@Override
+	public void appLeave(IClient client, IScope scope) {
+		log.debug(APP + ":appLeave " + scope.getName());
+	}
+
+	@Override
+	public boolean appStart(IScope scope) {
+		log.debug(APP + ":appStart " + scope.getName());
+		return true;
+	}
+
+	@Override
+	public void appStop(IScope scope) {
+		log.debug(APP + ":appStop " + scope.getName());
+	}
+
+	@Override
+	public boolean roomConnect(IConnection connection, Object[] params) {
+		log.debug(APP + ":roomConnect");
+		ISharedObject so = getSharedObject(connection.getScope(), LAYOUT_SO);
+		log.debug("Setting up Listener");
+		LayoutSender sender = new LayoutSender(so);
+		String room = connection.getScope().getName();
+		log.debug("Adding event listener to " + room);
+		log.debug("Adding room listener");
+		layoutApplication.addRoomListener(room, sender);
+		log.debug("Done setting up listener");
+		return true;
+	}
+
+	@Override
+	public void roomDisconnect(IConnection connection) {
+		log.debug(APP + ":roomDisconnect");
+	}
+
+	@Override
+	public boolean roomJoin(IClient client, IScope scope) {
+		log.debug(APP + ":roomJoin " + scope.getName() + " - " + scope.getParent().getName());
+		return true;
+	}
+
+	@Override
+	public void roomLeave(IClient client, IScope scope) {
+		log.debug(APP + ":roomLeave " + scope.getName());
+	}
+	
+	@Override
+	public boolean roomStart(IScope scope) {
+		log.debug(APP + ":roomStart " + scope.getName());
+		layoutApplication.createRoom(scope.getName());
+    	if (!hasSharedObject(scope, LAYOUT_SO)) {
+    		if (createSharedObject(scope, LAYOUT_SO, false)) {   
+    			return true;
+    		}    		
+    	}  	
+		log.error("Failed to start room " + scope.getName());
+    	return false;
+	}
+
+	@Override
+	public void roomStop(IScope scope) {
+		log.debug(APP + ":roomStop " + scope.getName());
+		layoutApplication.destroyRoom(scope.getName());
+		if (!hasSharedObject(scope, LAYOUT_SO)) {
+    		clearSharedObjects(scope, LAYOUT_SO);
+    	}
+	}
+	
+	public void setLayoutApplication(LayoutApplication a) {
+		log.debug("Setting layout application");
+		layoutApplication = a;
+		layoutApplication.handler = this;
+	}
+	
+}
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutRoom.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutRoom.java
new file mode 100755
index 0000000000000000000000000000000000000000..fe4b7ee1990f097da271496804907ede189a99ab
--- /dev/null
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutRoom.java
@@ -0,0 +1,96 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.conference.service.layout;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import net.jcip.annotations.ThreadSafe;
+
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+/**
+ * Contains information about a LayoutRoom. 
+ */
+@ThreadSafe
+public class LayoutRoom {
+	private static Logger log = Red5LoggerFactory.getLogger( LayoutRoom.class, "bigbluebutton" );
+	
+	private final String name;
+	private final Map<String, ILayoutRoomListener> listeners;
+	private boolean locked = false;
+	private int modifierId = -1;
+	private String currentLayout = "";
+	
+	public LayoutRoom(String name) {
+		this.name = name;
+		this.listeners = new ConcurrentHashMap<String, ILayoutRoomListener>();
+	}
+	
+	public String getName() {
+		return name;
+	}
+	
+	public void addRoomListener(ILayoutRoomListener listener) {
+		if (! listeners.containsKey(listener.getName())) {
+			log.debug("adding room listener");
+			listeners.put(listener.getName(), listener);			
+		}
+	}
+	
+	public void removeRoomListener(ILayoutRoomListener listener) {
+		log.debug("removing room listener");
+		listeners.remove(listener);		
+	}
+	
+	private void updateLayout() {
+		for (Iterator<ILayoutRoomListener> iter = listeners.values().iterator(); iter.hasNext();) {
+			log.debug("calling on listener");
+			ILayoutRoomListener listener = (ILayoutRoomListener) iter.next();
+			log.debug("calling updateLayout on listener " + listener.getName());
+			listener.updateLayout(currentLayout());
+		}
+	}
+		
+	public void lockLayout(int userId, String layout) {
+		locked = true;
+		modifierId = userId;
+		currentLayout = layout;
+		updateLayout();
+	}
+
+	public void unlockLayout() {
+		locked = false;
+		modifierId = -1;
+		currentLayout = "";
+		updateLayout();
+	}
+
+	public List<Object> currentLayout() {
+		List<Object> args = new ArrayList<Object>();
+		args.add(locked);
+		args.add(modifierId);
+		args.add(currentLayout);
+		return args;
+	}
+}
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutRoomsManager.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutRoomsManager.java
new file mode 100755
index 0000000000000000000000000000000000000000..89715eb2fc4976a4cb30a77d919b8914926621d9
--- /dev/null
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutRoomsManager.java
@@ -0,0 +1,113 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.conference.service.layout;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import net.jcip.annotations.ThreadSafe;
+
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+/**
+ * This encapsulates access to LayoutRoom and messages. This class must be threadsafe.
+ */
+@ThreadSafe
+public class LayoutRoomsManager {
+	private static Logger log = Red5LoggerFactory.getLogger( LayoutRoomsManager.class, "bigbluebutton" );
+	
+	private final Map <String, LayoutRoom> rooms;
+	
+	public LayoutRoomsManager() {
+		log.debug("In LayoutRoomsManager constructor");	
+		rooms = new ConcurrentHashMap<String, LayoutRoom>();
+	}
+	
+	public void addRoom(LayoutRoom room) {
+		log.debug("In LayoutRoomsManager adding room " + room.getName());
+		rooms.put(room.getName(), room);
+	}
+	
+	public void removeRoom(String name) {
+		log.debug("In LayoutRoomsManager remove room " + name);
+		rooms.remove(name);
+	}
+		
+	public boolean hasRoom(String name) {
+		log.debug("In LayoutRoomsManager has Room " + name);
+		return rooms.containsKey(name);
+	}
+	
+	
+	/**
+	 * Keeping getRoom private so that all access to ChatRoom goes through here.
+	 */
+	private LayoutRoom getRoom(String name) {
+		log.debug("In LayoutRoomsManager get room " + name);
+		return rooms.get(name);
+	}
+	
+	public void addRoomListener(String roomName, ILayoutRoomListener listener) {
+		LayoutRoom r = getRoom(roomName);
+		if (r != null) {
+			r.addRoomListener(listener);
+			return;
+		}
+		log.warn("Adding listener to a non-existing room " + roomName);
+	}
+	
+	public void removeRoomListener(String roomName, ILayoutRoomListener listener) {
+		LayoutRoom r = getRoom(roomName);
+		if (r != null) {
+			r.removeRoomListener(listener);
+			return;
+		}	
+		log.warn("Removing listener to a non-existing room " + roomName);
+	}
+	
+	public void lockLayout(String room, int userId, String layout) {
+		LayoutRoom r = getRoom(room);
+		if (r != null) {
+			r.lockLayout(userId, layout);
+		} else {
+			log.warn("lockLayout: sending message to a non-existing room " + room);
+		}
+	} 
+
+	public void unlockLayout(String room) {
+		LayoutRoom r = getRoom(room);
+		if (r != null) {
+			r.unlockLayout();
+		} else {
+			log.warn("unlockLayout: sending message to a non-existing room " + room);
+		}
+	}
+
+	public List<Object> currentLayout(String room) {
+		LayoutRoom r = getRoom(room);
+		if (r != null) {
+			return r.currentLayout();
+		} else {
+			log.warn("initLayout: sending message to a non-existing room " + room);
+			return null;
+		}
+	}
+}
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutSender.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutSender.java
new file mode 100755
index 0000000000000000000000000000000000000000..1f0e7ff50983d1676b9d69f4faf189f210d8cc92
--- /dev/null
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutSender.java
@@ -0,0 +1,59 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.conference.service.layout;
+
+import java.util.List;
+
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.so.ISharedObject;
+import org.red5.server.api.statistics.ISharedObjectStatistics;
+import org.slf4j.Logger;
+
+public class LayoutSender implements ILayoutRoomListener {
+
+private static Logger log = Red5LoggerFactory.getLogger( LayoutSender.class, "bigbluebutton" );
+	
+	private ISharedObject so;
+	private String name = "LAYOUT";
+	
+	public LayoutSender(ISharedObject so) {
+		this.so = so; 
+	}
+
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	@Override
+	public void updateLayout(List<Object> args) {
+		log.debug("Sending update layout");
+		
+		if (so.isLocked()) log.info("Layout SO is locked");
+		if (so.isAcquired()) log.info("Layout SO is acquired");
+		ISharedObjectStatistics stats = so.getStatistics();
+		log.debug("Before: Layout SO stats [total-sends=" + stats.getTotalSends() + "]");
+		so.sendMessage("remoteUpdateLayout", args);
+		log.debug("After: Layout SO stats [total-sends=" + stats.getTotalSends() + "]");
+		if (so.isLocked()) log.info("Layout SO is locked");
+		if (so.isAcquired()) log.info("Layout SO is acquired");
+	}
+
+}
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutService.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutService.java
new file mode 100755
index 0000000000000000000000000000000000000000..be0348ef68c8116a9e51432a4a5c02695871bff5
--- /dev/null
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutService.java
@@ -0,0 +1,55 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.conference.service.layout;
+
import java.util.List;
+
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.Red5;
+import org.slf4j.Logger;
+
+public class LayoutService {
+	
+	private static Logger log = Red5LoggerFactory.getLogger( LayoutService.class, "bigbluebutton" );
+	
+	private LayoutApplication application;
+
+	public List<Object> init() {
+		log.debug("Initializing layout");
+		String roomName = Red5.getConnectionLocal().getScope().getName();
+		return application.currentLayout(roomName);
+	}
+	
+	public void lock(int userId, String layout) {
+		log.debug("Layout locked");
+		String roomName = Red5.getConnectionLocal().getScope().getName();
+		application.lockLayout(roomName, userId, layout);
+	}
+	
+	public void unlock() {
+		log.debug("Layout unlocked");
+		String roomName = Red5.getConnectionLocal().getScope().getName();
+		application.unlockLayout(roomName);
+	}
+	
+	public void setLayoutApplication(LayoutApplication a) {
+		log.debug("Setting layout application");
+		application = a;
+	}
+}
diff --git a/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-apps.xml b/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-apps.xml
index 0b1a7183b8ea70816ab15c5ff4e14e3f7d7c1dd7..e0acad00de434bcf3ecc417f2ed63f04acdb940d 100755
--- a/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-apps.xml
+++ b/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-apps.xml
@@ -27,6 +27,23 @@
 		<property name="participantsApplication"> <ref local="participantsApplication"/></property>
 	</bean>
 	
+	
+	<!-- BEGIN LAYOUT -->	
+	<bean id="layoutRoomsManager" class="org.bigbluebutton.conference.service.layout.LayoutRoomsManager"/>
+	
+	<bean id="layoutHandler" class="org.bigbluebutton.conference.service.layout.LayoutHandler">
+	    <property name="layoutApplication"><ref local="layoutApplication"/></property>
+	</bean>
+
+	<bean id="layoutApplication" class="org.bigbluebutton.conference.service.layout.LayoutApplication">
+		<property name="roomsManager"><ref local="layoutRoomsManager"/></property>
+	</bean>
+	
+	<bean id="layout.service" class="org.bigbluebutton.conference.service.layout.LayoutService">
+	    <property name="layoutApplication"><ref local="layoutApplication"/></property>
+   	</bean>	
+	<!-- END LAYOUT -->	
+		
 	<!-- BEGIN PRESENTATION -->	
 	<bean id="presentationRoomsManager" class="org.bigbluebutton.conference.service.presentation.PresentationRoomsManager"/>
 			
diff --git a/bigbluebutton-apps/src/main/webapp/WEB-INF/red5-web.xml b/bigbluebutton-apps/src/main/webapp/WEB-INF/red5-web.xml
index 6b55275cf40813b22b9823383189eb6848a7a1d5..fa36b5981ea19f980f26252c8d816cbfc6c1eff1 100755
--- a/bigbluebutton-apps/src/main/webapp/WEB-INF/red5-web.xml
+++ b/bigbluebutton-apps/src/main/webapp/WEB-INF/red5-web.xml
@@ -32,6 +32,7 @@
     		<set>
 				<ref bean="participantsHandler" />
 				<ref bean="chatHandler" />
+				<ref bean="layoutHandler" />
 				<ref bean="presentationHandler" />
 				<ref bean="voiceHandler" />
 				<ref bean="whiteboardApplication" />
diff --git a/bigbluebutton-client/build.xml b/bigbluebutton-client/build.xml
index efc9e47b2364e8cb06bbeb052a55b42a1c06e722..d27038ccb04abdc18a7706d3ff72766ca4dd0b50 100755
--- a/bigbluebutton-client/build.xml
+++ b/bigbluebutton-client/build.xml
@@ -31,6 +31,7 @@
 	<property name="CLASSROOM_AUDIO" value="ClassroomAudioModule" />
 	<property name="SETTINGS" value="SettingsModule" />
 	<property name="VIDEO_DOCK" value="VideodockModule" />
+	<property name="LAYOUT" value="LayoutModule" />
 	
 	<xmlproperty file="${SRC_DIR}/conf/locales.xml" collapseAttributes="true"/>
 	
@@ -231,9 +232,13 @@
 		<build-module src="${SRC_DIR}" target="${DYN_INFO}" />
 	</target>
 	
+	<target name="build-layout" description="Compile Layout Module">
+		<build-module src="${SRC_DIR}" target="${LAYOUT}" />
+	</target>
+	
 	<!-- just a grouping of modules to compile -->
 	<target name="build-main-chat-viewers-listeners-present" 
-			depends="build-bbb-main, build-bbb-main-test, build-chat, build-viewers, build-listeners, build-present, build-breakout"
+			depends="build-bbb-main, build-bbb-main-test, build-chat, build-viewers, build-listeners, build-present, build-breakout, build-layout"
 			description="Compile main, chat, viewers, listeners, present, breakout modules">
 	</target>
 	
@@ -378,18 +383,20 @@
 		<copy file="${PROD_RESOURCES_DIR}/expressInstall.swf" todir="${OUTPUT_DIR}" overwrite="true"/>	
 		<copy file="${PROD_RESOURCES_DIR}/example-info-data.xml" todir="${OUTPUT_DIR}/conf" overwrite="true"/>
 		<if>
-           	   <equals arg1="${BUILD_ENV}" arg2="DEV"/>
-           	      <then>
-              			<echo message="Copying config.xml for development environment"/>
+			<equals arg1="${BUILD_ENV}" arg2="DEV"/>
+			<then>
+				<echo message="Copying config.xml for development environment"/>
 				<copy file="${BASE_DIR}/src/conf/config.xml" todir="${OUTPUT_DIR}/conf" /> 
-              			<echo message="Copying join-mock.xml for development environment"/>
+				<echo message="Copying join-mock.xml for development environment"/>
 				<copy file="${BASE_DIR}/src/conf/join-mock.xml" todir="${OUTPUT_DIR}/conf" /> 
-           		</then>
-           	<else>
-              		<echo message="Need to copy config.xml.template for production environment"/>
-			<copy file="${RESOURCES_DIR}/config.xml.template" todir="${OUTPUT_DIR}/conf" overwrite="true"/>		
-           	</else>
-        	</if>
+				<echo message="Copying layout.xml for development environment"/>
+				<copy file="${BASE_DIR}/src/conf/layout.xml" todir="${OUTPUT_DIR}/conf" /> 
+			</then>
+			<else>
+				<echo message="Need to copy config.xml.template for production environment"/>
+				<copy file="${RESOURCES_DIR}/config.xml.template" todir="${OUTPUT_DIR}/conf" overwrite="true"/>		
+			</else>
+		</if>
 	</target>
 	
 
diff --git a/bigbluebutton-client/locale/en_US/bbbResources.properties b/bigbluebutton-client/locale/en_US/bbbResources.properties
index c345b3038a8bbee8d3f55dad4248ba5374386f28..f0f38cc855b96f49758307c80c86194b1800f3fb 100755
--- a/bigbluebutton-client/locale/en_US/bbbResources.properties
+++ b/bigbluebutton-client/locale/en_US/bbbResources.properties
@@ -132,6 +132,18 @@ bbb.desktopView.actualSize = Display actual size
 bbb.toolbar.phone.toolTip = Share My Microphone
 bbb.toolbar.deskshare.toolTip = Share My Desktop
 bbb.toolbar.video.toolTip = Share My Camera
+bbb.layout.addButton.toolTip = Add the custom layout to the list
+bbb.layout.combo.toolTip = Change the current layout
+bbb.layout.loadButton.toolTip = Load layouts from a file
+bbb.layout.saveButton.toolTip = Save layouts to a file
+bbb.layout.lockButton.toolTip = Lock layout
+bbb.layout.combo.prompt = Apply a layout
+bbb.layout.combo.custom = * Custom layout
+bbb.layout.combo.customName = Custom layout
+bbb.layout.combo.remote = Remote
+bbb.layout.save.complete = Layouts were successfully saved
+bbb.layout.load.complete = Layouts were successfully loaded
+bbb.layout.load.failed = Failed to load the layouts
 bbb.highlighter.toolbar.pencil = Highlighter
 bbb.highlighter.toolbar.ellipse = Circle
 bbb.highlighter.toolbar.rectangle = Rectangle
diff --git a/bigbluebutton-client/resources/config.xml.template b/bigbluebutton-client/resources/config.xml.template
index 5fcc26e00324cea8e6ccaf5dafa2924f57b353cf..495b73762a7ea9fc06cd1865ce3cdf26c3cef85a 100755
--- a/bigbluebutton-client/resources/config.xml.template
+++ b/bigbluebutton-client/resources/config.xml.template
@@ -95,6 +95,12 @@
 			oneAlwaysBigger="false"
 		/>
 		
+		<module name="LayoutModule" url="LayoutModule.swf?v=VERSION"
+			uri="rtmp://HOST/bigbluebutton"
+			layoutConfig="conf/layout.xml"
+			enableEdit="true"
+		/>
+
 		<!-- new module in development: 
 		<module name="DynamicInfoModule" url="DynamicInfoModule.swf?v=VERSION" 
 			uri="rtmp://HOST/bigbluebutton" 
diff --git a/bigbluebutton-client/src/LayoutModule.mxml b/bigbluebutton-client/src/LayoutModule.mxml
new file mode 100755
index 0000000000000000000000000000000000000000..45d939f1afbcbc3f88da86d67312840d3be09c2a
--- /dev/null
+++ b/bigbluebutton-client/src/LayoutModule.mxml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+  Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+  This program 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; either version 2.1 of the License, or (at your option) any later
+  version.
+
+  BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+  Author: Felipe Cecagno <felipe@mconf.org>
+
+  $Id: $
+-->
+<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
+			xmlns:maps="org.bigbluebutton.modules.layout.maps.*" 
+			implements="org.bigbluebutton.common.IBigBlueButtonModule">
+	
+	<maps:LayoutEventMap id="layoutEventMap" />
+	
+	<mx:Script>
+		<![CDATA[
+			import com.asfusion.mate.events.Dispatcher;
+
+			import org.bigbluebutton.common.LogUtil;
+			import org.bigbluebutton.modules.layout.events.StartLayoutModuleEvent;
+			import org.bigbluebutton.modules.layout.events.LayoutEvent;
+			
+			private var _moduleName:String = "Layout Module";
+			private var _globalDispatcher:Dispatcher = new Dispatcher();
+			
+			private function onCreationComplete():void {
+				LogUtil.debug(_moduleName + " initialized");	
+			}
+			
+			public function get moduleName():String {
+				return _moduleName;
+			}
+			
+			public function start(attributes:Object):void {
+				var event:StartLayoutModuleEvent = new StartLayoutModuleEvent();
+				event.attributes = attributes;
+				_globalDispatcher.dispatchEvent(event);
+			}
+			
+			public function stop():void {
+				var event:LayoutEvent = new LayoutEvent(LayoutEvent.STOP_LAYOUT_MODULE_EVENT);
+				_globalDispatcher.dispatchEvent(event);
+			}
+			
+		]]>
+	</mx:Script>
+</mx:Module>
\ No newline at end of file
diff --git a/bigbluebutton-client/src/conf/layout.xml b/bigbluebutton-client/src/conf/layout.xml
new file mode 100644
index 0000000000000000000000000000000000000000..47ec87b4b10230f505a4f8af0ed2e25189c8cf7e
--- /dev/null
+++ b/bigbluebutton-client/src/conf/layout.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<layouts>
+	<layout name="Default" default="true">
+		<window name="ViewersWindow" width="0.1772793053545586" height="0.33643617021276595" x="0" y="0" />
+		<window name="ListenersWindow" width="0.1772793053545586" height="0.33643617021276595" x="0" y="0.34308510638297873" />
+		<window name="PresentationWindow" width="0.5137481910274964" height="0.9946808510638298" x="0.18017366136034732" y="0" />
+		<window name="VideoDock" width="0.1772793053545586" height="0.30851063829787234" x="0" y="0.6875" />
+		<window name="ChatWindow" width="0.3031837916063676" height="0.9960106382978723" x="0.6968162083936325" y="0" />
+	</layout>
+	<layout name="Meeting">
+		<window name="VideoDock" width="0.6570188133140377" height="0.9960106382978723" x="0" y="0" />
+		<window name="ChatWindow" width="0.3393632416787265" height="0.5305851063829787" x="0.658465991316932" y="0" />
+		<window name="ListenersWindow" hidden="true" />
+		<window name="ViewersWindow" hidden="true" />
+		<window name="PresentationWindow" width="0.34008683068017365" height="0.4601063829787234" x="0.658465991316932" y="0.535904255319149" />
+	</layout>
+	<layout name="Webinar">
+		<window name="ViewersWindow" minimized="true" />
+		<window name="VideoDock" width="0.2923611111111111" height="0.4640957446808511" x="0.7048611111111112" y="0.535904255319149" />
+		<window name="ListenersWindow" minimized="true" />
+		<window name="PresentationWindow" width="0.7027777777777777" height="0.9986702127659575" x="0" y="0" />
+		<window name="ChatWindow" width="0.2923611111111111" height="0.5305851063829787" x="0.7048611111111112" y="0" />
+	</layout>
+	<layout name="Lecture assistant">
+		<window name="ChatWindow" width="0.4597222222222222" height="0.9958677685950413" x="0.2263888888888889" y="0" />
+		<window name="ListenersWindow" width="0.2222222222222222" height="0.4765840220385675" x="0" y="0.5179063360881543" />
+		<window name="ViewersWindow" width="0.22152777777777777" height="0.5055096418732782" x="0" y="0" />
+		<window name="PresentationWindow" width="0.3104166666666667" height="0.5537190082644629" x="0.6895833333333333" y="0" />
+		<window name="VideoDock" width="0.30972222222222223" height="0.4256198347107438" x="0.6902777777777778" y="0.568870523415978" />
+	</layout>	
+	<layout name="Lecture">
+		<window name="ViewersWindow" hidden="true" />
+		<window name="VideoDock" width="0.2923611111111111" height="0.4640957446808511" x="0.7048611111111112" y="0.535904255319149" />
+		<window name="ListenersWindow" hidden="true" />
+		<window name="PresentationWindow" width="0.7027777777777777" height="0.9986702127659575" x="0" y="0" />
+		<window name="ChatWindow" width="0.2923611111111111" height="0.5305851063829787" x="0.7048611111111112" y="0" />
+	</layout>	
+	<layout name="Lecture" role="presenter">
+		<window name="ChatWindow" hidden="true" />
+		<window name="ListenersWindow" hidden="true" />
+		<window name="ViewersWindow" hidden="true" />
+		<window name="PresentationWindow" maximized="true" />
+		<window name="VideoDock" hidden="true" />
+	</layout>	
+	<layout name="Lecture" role="moderator">
+   		<window name="ChatWindow" width="0.4597222222222222" height="0.9958677685950413" x="0.2263888888888889" y="0" />
+		<window name="ListenersWindow" width="0.2222222222222222" height="0.4765840220385675" x="0" y="0.5179063360881543" />
+		<window name="ViewersWindow" width="0.22152777777777777" height="0.5055096418732782" x="0" y="0" />
+		<window name="PresentationWindow" width="0.3104166666666667" height="0.5537190082644629" x="0.6895833333333333" y="0" />
+		<window name="VideoDock" width="0.30972222222222223" height="0.4256198347107438" x="0.6902777777777778" y="0.568870523415978" />
+		</layout>	
+</layouts>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/Images.as b/bigbluebutton-client/src/org/bigbluebutton/common/Images.as
index 425075e6e81d552b21b5de334a7e0e9fedb4d76c..79c38b53e48ca797d6869f8b9a474d4dbd9a6099 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/common/Images.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/common/Images.as
@@ -173,5 +173,11 @@ package org.bigbluebutton.common
 		
 		[Embed(source="assets/images/shape_handles.png")]
 		public var shape_handles:Class;		
+
+		[Embed(source="assets/images/disk.png")]
+		public var disk:Class;		
+
+		[Embed(source="assets/images/folder.png")]
+		public var folder:Class;		
 	}
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/disk.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/disk.png
new file mode 100644
index 0000000000000000000000000000000000000000..99d532e8b1750115952f97302a92d713c0486f97
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/disk.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/folder.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/folder.png
new file mode 100644
index 0000000000000000000000000000000000000000..784e8fa48234f4f64b6922a6758f254ee0ca08ec
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/folder.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/events/ToolbarButtonEvent.as b/bigbluebutton-client/src/org/bigbluebutton/common/events/ToolbarButtonEvent.as
index f6a2ba324379dcfddd63e9a6e96b54f938d53c75..e31b44334e2098a135b08fc1d81ab98ab840edf9 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/common/events/ToolbarButtonEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/common/events/ToolbarButtonEvent.as
@@ -31,11 +31,13 @@ package org.bigbluebutton.common.events
 	{
 		public static const ADD:String = "Add Toolbar Button Event";
 		public static const REMOVE:String = "Remove Toolbar Button Event";
-		
+		public static const TOP_TOOLBAR:String = "Top Toolbar";
+		public static const BOTTOM_TOOLBAR:String = "Bottom Toolbar";
 		/**
 		 * The ui component to add to the toolbar. 
 		 */		
 		public var button:IBbbToolbarComponent;
+		public var location:String = TOP_TOOLBAR;
 		
 		public function ToolbarButtonEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
 		{
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModuleManager.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModuleManager.as
index 1b08994d342b22b187344975827a9a36f6276973..9fbdee58cfab5ae7fa7bf513d6fd93dc218cc656 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModuleManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModuleManager.as
@@ -103,7 +103,7 @@ package org.bigbluebutton.main.model.modules
 			if (m != null) {
 				LogUtil.debug('Stopping ' + name);
 				var bbb:IBigBlueButtonModule = m.module as IBigBlueButtonModule;
-				if(bbb == null) { //Still has null object refrence on logout sometimes.
+				if(bbb == null) { //Still has null object reference on logout sometimes.
 					LogUtil.debug('Module ' + name + ' was null skipping');
 					return;
 				}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/LanguageSelector.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/LanguageSelector.mxml
index 348676283b82febfce6f5b42a92c1e7ed8216413..4a6244560f049db9fb9848ad34fe4b7b7b9af82e 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/LanguageSelector.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/LanguageSelector.mxml
@@ -22,7 +22,7 @@
 
 <mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml" dataProvider="{ResourceUtil.getInstance().localeNames}" 
 			 selectedIndex="{ResourceUtil.getInstance().localeIndex}"
-			 change="changeLanguage()" rowCount="15" width="120">
+			 change="changeLanguage()" rowCount="15" width="120" height="22">
 	<mx:Script>
 		<![CDATA[
 			import org.bigbluebutton.util.i18n.ResourceUtil;
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml
index 482c427ecf60b9322952d211fa463b98d7affb1e..2d7d8ed8e087f9113a7396bb7b6ad56672e71386 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml
@@ -41,6 +41,8 @@
 	<mate:Listener type="{ConnectionFailedEvent.CONNECTION_REJECTED}" method="attemptReconnect"  />
 	<mate:Listener type="configLoadedEvent" method="initOptions"  />
 	<mate:Listener type="SHOW_MIC_SETTINGS" method="showMicSettings"  />
+	<mate:Listener type="{ToolbarButtonEvent.ADD}" method="handleAddToolbarComponent" />	
+	<mate:Listener type="{ToolbarButtonEvent.REMOVE}" method="handleRemoveToolbarComponent"/>
 	
 	<mx:Script>
 		<![CDATA[
@@ -55,6 +57,7 @@
 			import mx.containers.TitleWindow;
 			import mx.controls.Alert;
 			import mx.core.FlexGlobals;
+			import mx.core.UIComponent;
 			import mx.events.CloseEvent;
 			import mx.managers.PopUpManager;
 			
@@ -64,6 +67,7 @@
 			import org.bigbluebutton.common.events.AddUIComponentToMainCanvas;
 			import org.bigbluebutton.common.events.CloseWindowEvent;
 			import org.bigbluebutton.common.events.OpenWindowEvent;
+			import org.bigbluebutton.common.events.ToolbarButtonEvent;
 			import org.bigbluebutton.core.BBB;
 			import org.bigbluebutton.main.events.AppVersionEvent;
 			import org.bigbluebutton.main.events.BBBEvent;
@@ -133,10 +137,10 @@
 					receivedConfigLocaleVer = true;
 					appVersion = event.appVersion;
 					localeVersion = event.localeVersion;
-					LogUtil.debug("Received locale version fron config.xml");
+					LogUtil.debug("Received locale version from config.xml");
 				} else {
 					receivedResourceLocaleVer = true;
-					LogUtil.debug("Received locale version fron locale file.");
+					LogUtil.debug("Received locale version from locale file.");
 				}
 				
 				if (receivedConfigLocaleVer && receivedResourceLocaleVer) {
@@ -298,20 +302,33 @@
 				Alert.show(evt.status, evt.module);
 			}
 						
+			private function handleAddToolbarComponent(event:ToolbarButtonEvent):void {
+				if (event.location == ToolbarButtonEvent.BOTTOM_TOOLBAR) {
+					addedBtns.addChild(event.button as UIComponent);
+//					realignButtons();
+				}
+			}
+			
+			private function handleRemoveToolbarComponent(event:ToolbarButtonEvent):void {
+				if (addedBtns.contains(event.button as UIComponent))
+					addedBtns.removeChild(event.button as UIComponent);
+			}
+			
 		]]>
 	</mx:Script>
 			
-	<views:MainToolbar id="toolbar" dock="true" width="100%" height="30" visible="{showToolbarOpt}" verticalAlign="middle" toolbarOptions="{layoutOptions}"/>
+	<views:MainToolbar id="toolbar" dock="true" width="100%" height="30" visible="{showToolbarOpt}" verticalAlign="middle" toolbarOptions="{layoutOptions}" paddingTop="4"/>
 	<views:MainCanvas id="mdiCanvas" horizontalScrollPolicy="off" verticalScrollPolicy="off" effectsLib="{flexlib.mdi.effects.effectsLib.MDIVistaEffects}" width="100%" height="100%">
 		<views:LoadingBar id="progressBar" x="{this.width/2 - progressBar.width/2}" y="{this.height/2 - progressBar.height/2}" width="{this.width/2}" />
 		<views:BrandingLogo x="{this.width - 300}" y="{this.height - 300}" />
 	</views:MainCanvas>	
 	
-	<mx:ControlBar width="100%" height="20" paddingTop="0">		
+	<mx:ControlBar width="100%" height="24" paddingTop="0">
 	  	<mx:Label text="{ResourceUtil.getInstance().getString('bbb.mainshell.copyrightLabel2',[appVersion])}" id="copyrightLabel2"/>
 	 	<mx:Spacer width="20"/>
 		<mx:Spacer width="100%"/> 
 		<mx:Button width="20" height="20" visible="{layoutOptions.showLogButton}" toolTip="{ResourceUtil.getInstance().getString('bbb.mainshell.logBtn.toolTip')}" id="logBtn" icon="{logs_icon}" click="openLogWindow()" />
-		<mx:Button width="20" height="20" visible="{layoutOptions.showResetLayout}" toolTip="{ResourceUtil.getInstance().getString('bbb.mainshell.resetLayoutBtn.toolTip')}" id="btnResetLayout" icon="{reset_layout_icon}" click="resetLayout()" />
+		<!-- mx:Button width="20" height="20" visible="{layoutOptions.showResetLayout}" toolTip="{ResourceUtil.getInstance().getString('bbb.mainshell.resetLayoutBtn.toolTip')}" id="btnResetLayout" icon="{reset_layout_icon}" click="resetLayout()" /-->
+		<mx:HBox id="addedBtns" />
 	</mx:ControlBar>
 </mx:VBox>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainCanvas.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainCanvas.mxml
index 76440141fa2ee2c79bd9345249b69812869a5995..68fd1874a73bc4c0500bbe00fcb976dc9f58a483 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainCanvas.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainCanvas.mxml
@@ -201,75 +201,6 @@
 				windowManager.absPos(win, x, y);
 			}
 			
-			private function getVideoWindows():Array
-			{
-				var windows:Array = this.windowManager.getOpenWindowList();
-				var videowindows:Array = new Array();
-				for (var i:Number=0; i<windows.length; i++) {
-					var window:IBbbModuleWindow = windows[i] as IBbbModuleWindow;
-					var type:String = getType(window);
-					if (type == "PublishWindow" || type == "VideoWindow")
-						videowindows.push(window);
-				}
-				return videowindows;
-			}
-			
-			private function getType(window:IBbbModuleWindow):String {
-				return String(window).substr(String(window).lastIndexOf(".") + 1).match(/[a-zA-Z]+/).join();
-			}
-			
-			public function layoutSmallVideos():void
-			{
-				var windows:Array = getVideoWindows();
-				if (windows.length == 0)
-					return;
-					
-				var width:int = 166;
-				var height:int = 149;
-				
-				var rows:int = Math.ceil(this.height/height);
-				var winPerRow:int = Math.floor(windows.length/rows);
-
-				// try to fit better the number of windows per row
-				winPerRow = Math.floor(this.width / width);
-				rows = Math.ceil(windows.length / winPerRow);
-				while (Math.ceil(windows.length / (winPerRow - 1)) == rows) {
-					winPerRow -= 1;
-				}
-
-				var x:int = 0;
-				var y:int = this.height;
-							
-				for (var i:Number=0; i<windows.length; i++) {
-					var window:IBbbModuleWindow = windows[i] as IBbbModuleWindow;
-					var type:String = getType(window);
-					
-					(window as MDIWindow).width = width;
-					
-					var win:MDIWindow = window as MDIWindow;
-					if (win.minimized || win.maximized)
-						win.restore();
-					windowManager.bringToFront(win);
-					
-					// change the row
-					if (i % winPerRow == 0) {
-						x = Math.floor((this.width - (width * winPerRow)) / 2);
-						y -= height;
-					}
-
-					windowManager.absPos(win, x, y);
-					x += win.width;
-				}				
-			}
-			
-			public function layoutPresenter():void
-			{
-			}
-			
-			public function layoutMeeting():void
-			{
-			}
-			
 		]]>
 	</mx:Script>
 	
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainToolbar.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainToolbar.mxml
index 33702bd91e4d7541f0db38876be20e7ea5649d0a..cb7637ad0aca0a0c9652bbe0255f7b71d5577204 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainToolbar.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainToolbar.mxml
@@ -111,12 +111,15 @@
 			}
 			
 			private function handleAddToolbarButtonEvent(event:ToolbarButtonEvent):void {
-				addedBtns.addChild(event.button as UIComponent);
-				realignButtons();
+				if (event.location == ToolbarButtonEvent.TOP_TOOLBAR) {
+					addedBtns.addChild(event.button as UIComponent);
+					realignButtons();
+				}
 			}
 			
 			private function handleRemoveToolbarButtonEvent(event:ToolbarButtonEvent):void {
-				addedBtns.removeChild(event.button as UIComponent);
+				if (addedBtns.contains(event.button as UIComponent))
+					addedBtns.removeChild(event.button as UIComponent);
 			}
 			
 			private function realignButtons():void{
@@ -153,11 +156,10 @@
 			
 		]]>
 	</mx:Script>	
-	<mx:HBox id="addedBtns">
-	</mx:HBox>		
+	<mx:HBox id="addedBtns"/>
 	<mx:Spacer width="100%"/>
 	<views:LanguageSelector id="langSelector" visible="false" />
-	<mx:LinkButton id="helpBtn" label="{ResourceUtil.getInstance().getString('bbb.mainToolbar.helpBtn')}" visible="{showHelpBtn}" click="onHelpButtonClicked()"/>
+	<mx:LinkButton id="helpBtn" label="{ResourceUtil.getInstance().getString('bbb.mainToolbar.helpBtn')}" visible="{showHelpBtn}" click="onHelpButtonClicked()" height="22"/>
 	<mx:Button label="{ResourceUtil.getInstance().getString('bbb.mainToolbar.logoutBtn')}" id="btnLogout" 
-			   toolTip="{ResourceUtil.getInstance().getString('bbb.mainToolbar.logoutBtn.toolTip')}" right="10" click="doLogout()"/>
+			   toolTip="{ResourceUtil.getInstance().getString('bbb.mainToolbar.logoutBtn.toolTip')}" right="10" click="doLogout()" height="22"/>
 </mx:ApplicationControlBar>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/ConnectionEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/ConnectionEvent.as
new file mode 100755
index 0000000000000000000000000000000000000000..2efb56d72d438361056967793f86bf96c9b92afb
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/ConnectionEvent.as
@@ -0,0 +1,35 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program 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; either version 2.1 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+* 
+*/
+package org.bigbluebutton.modules.layout.events
+{
+	import flash.events.Event;
+
+	public class ConnectionEvent extends Event
+	{
+		public static const CONNECT_EVENT:String = 'CONNECT_EVENT';
+		public var success:Boolean = false;
+		public var errors:Array;
+		
+		public function ConnectionEvent(type:String=CONNECT_EVENT, bubbles:Boolean=false, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+		
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/LayoutEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/LayoutEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..d66559b3a9451da003376a67c3877cceda335ade
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/LayoutEvent.as
@@ -0,0 +1,47 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.modules.layout.events
+{
+	import flash.events.Event;
+
+	public class LayoutEvent extends Event
+	{
+		public static const REMOTE_LOCK_LAYOUT_EVENT:String = 'REMOTE_LOCK_LAYOUT_EVENT';
+		public static const REMOTE_UNLOCK_LAYOUT_EVENT:String = 'REMOTE_UNLOCK_LAYOUT_EVENT';
+
+		public static const LOCK_LAYOUT_EVENT:String = 'LOCK_LAYOUT_EVENT';
+		public static const UNLOCK_LAYOUT_EVENT:String = 'UNLOCK_LAYOUT_EVENT';
+		public static const STOP_LAYOUT_MODULE_EVENT:String = 'STOP_LAYOUT_MODULE_EVENT';
+		public static const VIEW_INITIALIZED_EVENT:String = 'VIEW_INITIALIZED_EVENT';
+		
+		public static const SAVE_LAYOUTS_EVENT:String = 'SAVE_LAYOUTS_EVENT';
+		public static const LOAD_LAYOUTS_EVENT:String = 'LOAD_LAYOUTS_EVENT';
+		public static const ADD_CURRENT_LAYOUT_EVENT:String = 'ADD_CURRENT_LAYOUT_EVENT';
+		public static const FILE_LOADED_SUCCESSFULLY_EVENT:String = 'FILE_LOADED_SUCCESSFULLY_EVENT';
+		public static const APPLY_DEFAULT_LAYOUT_EVENT:String = 'APPLY_DEFAULT_LAYOUT_EVENT';
+		public static const INVALIDATE_LAYOUT_EVENT:String = 'INVALIDATE_LAYOUT_EVENT';
+		
+		public function LayoutEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+		
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/LayoutsLoadedEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/LayoutsLoadedEvent.as
new file mode 100755
index 0000000000000000000000000000000000000000..ba5a85db3e358d32d9951237c456a9fb5bea6e29
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/LayoutsLoadedEvent.as
@@ -0,0 +1,38 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.modules.layout.events
+{
+	import flash.events.Event;
+	import org.bigbluebutton.modules.layout.model.LayoutDefinitionFile;
+	
+	public class LayoutsLoadedEvent extends Event
+	{
+		public static const LAYOUTS_LOADED_EVENT:String = "LAYOUTS_LOADED_EVENT";
+		public var layouts:LayoutDefinitionFile = null;
+		public var success:Boolean = false;
+		public var error:TypeError = null;
+		
+		public function LayoutsLoadedEvent(type:String = LAYOUTS_LOADED_EVENT)
+		{
+			super(type, true, false);
+		}
+
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/RedefineLayoutEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/RedefineLayoutEvent.as
new file mode 100755
index 0000000000000000000000000000000000000000..ed3a328fe6a633e6d22b81b327469d791015b22c
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/RedefineLayoutEvent.as
@@ -0,0 +1,38 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.modules.layout.events
+{
+	import flash.events.Event;
+	
+	import org.bigbluebutton.modules.layout.model.LayoutDefinition;
+	
+	public class RedefineLayoutEvent extends Event
+	{
+		public static const REDEFINE_LAYOUT_EVENT:String = "REDEFINE_LAYOUT_EVENT";
+		public var layout:LayoutDefinition = null;
+		public var remote:Boolean = false;
+		
+		public function RedefineLayoutEvent(type:String = REDEFINE_LAYOUT_EVENT)
+		{
+			super(type, true, false);
+		}
+
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/StartLayoutModuleEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/StartLayoutModuleEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..eaa21782762213071d3e37070eef3608ab9f448d
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/StartLayoutModuleEvent.as
@@ -0,0 +1,35 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.modules.layout.events
+{
+	import flash.events.Event;
+
+	public class StartLayoutModuleEvent extends Event
+	{
+		public static const START_LAYOUT_MODULE_EVENT:String = 'START_LAYOUT_MODULE_EVENT';
+		public var attributes:Object;
+				
+		public function StartLayoutModuleEvent(type:String=START_LAYOUT_MODULE_EVENT, bubbles:Boolean=true, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+		
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/UpdateLayoutEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/UpdateLayoutEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..c9cbd34bb074206af9074762cc8dfc19b151bff4
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/UpdateLayoutEvent.as
@@ -0,0 +1,37 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.modules.layout.events
+{
+	import flash.events.Event;
+
+	import org.bigbluebutton.modules.layout.model.LayoutDefinition;
+
+	public class UpdateLayoutEvent extends Event
+	{
+		public static const UPDATE_LAYOUT_EVENT:String = 'UPDATE_LAYOUT_EVENT';
+		public var layout:LayoutDefinition;
+
+		public function UpdateLayoutEvent(type:String=UPDATE_LAYOUT_EVENT, bubbles:Boolean=true, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+		
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/ViewInitializedEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/ViewInitializedEvent.as
new file mode 100755
index 0000000000000000000000000000000000000000..727e0047073b8dd37d7623d814c2140895cb9abe
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/ViewInitializedEvent.as
@@ -0,0 +1,37 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.modules.layout.events
+{
+	import flash.events.Event;
+
+	import flexlib.mdi.containers.MDICanvas;
+	
+	public class ViewInitializedEvent extends Event
+	{
+		public static const VIEW_INITIALIZED_EVENT:String = "VIEW_INITIALIZED_EVENT";
+		public var canvas:MDICanvas = null;
+		
+		public function ViewInitializedEvent(type:String = VIEW_INITIALIZED_EVENT)
+		{
+			super(type, true, false);
+		}
+
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/managers/LayoutManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/managers/LayoutManager.as
new file mode 100755
index 0000000000000000000000000000000000000000..1277741033dd137d78cd2c4fdbc5b3df2193843a
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/managers/LayoutManager.as
@@ -0,0 +1,306 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.modules.layout.managers
+{
+	import com.asfusion.mate.events.Dispatcher;
+
+	import flash.events.Event;
+	import flash.events.EventDispatcher;
+	import flash.events.TimerEvent;
+	import flash.net.FileReference;
+	import flash.net.URLLoader;
+	import flash.net.URLRequest;
+	import flash.utils.Dictionary;
+	import flash.utils.Timer;
+	
+	import flexlib.mdi.containers.MDICanvas;
+	import flexlib.mdi.containers.MDIWindow;
+	import flexlib.mdi.events.MDIManagerEvent;
+
+	import mx.controls.Alert;
+	import mx.events.ResizeEvent;
+
+	import org.bigbluebutton.common.LogUtil;
+	import org.bigbluebutton.core.EventBroadcaster;
+	import org.bigbluebutton.core.managers.UserManager;
+	import org.bigbluebutton.core.model.Config;
+	import org.bigbluebutton.modules.layout.events.LayoutEvent;
+	import org.bigbluebutton.modules.layout.events.LayoutsLoadedEvent;
+	import org.bigbluebutton.modules.layout.events.UpdateLayoutEvent;
+	import org.bigbluebutton.modules.layout.model.LayoutDefinition;
+	import org.bigbluebutton.modules.layout.model.LayoutDefinitionFile;
+	import org.bigbluebutton.modules.layout.model.LayoutLoader;
+	import org.bigbluebutton.modules.layout.model.WindowLayout;
+	import org.bigbluebutton.modules.layout.events.RedefineLayoutEvent;
+	import org.bigbluebutton.util.i18n.ResourceUtil;
+	
+	public class LayoutManager extends EventDispatcher {
+		private var _layouts:LayoutDefinitionFile = null;
+		private var _canvas:MDICanvas = null;
+		private var _globalDispatcher:Dispatcher = new Dispatcher();
+		private var _locked:Boolean = false;
+		private var _currentLayout:LayoutDefinition = null;
+		private var _detectContainerChange:Boolean = true;
+		private var _containerDeactivated:Boolean = false;
+		private var _sendCurrentLayoutUpdateTimer:Timer = new Timer(500,1);
+		private var _applyCurrentLayoutTimer:Timer = new Timer(150,1);
+		private var _customLayoutsCount:int = 0;
+		private var _eventsToDelay:Array = new Array(MDIManagerEvent.WINDOW_RESTORE,
+				MDIManagerEvent.WINDOW_MINIMIZE,
+				MDIManagerEvent.WINDOW_MAXIMIZE);
+		
+		
+		public function LayoutManager() {
+			_applyCurrentLayoutTimer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void {
+				applyLayout(_currentLayout);
+			});
+			_sendCurrentLayoutUpdateTimer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void {
+				sendLayoutUpdate(updateCurrentLayout());
+			});
+		}
+		
+		public function loadServerLayouts(layoutUrl:String):void {
+			LogUtil.debug("LayoutManager: loading server layouts from " + layoutUrl);
+			var loader:LayoutLoader = new LayoutLoader();
+			loader.addEventListener(LayoutsLoadedEvent.LAYOUTS_LOADED_EVENT, function(e:LayoutsLoadedEvent):void {
+				if (e.success) {
+					_layouts = e.layouts;
+					LogUtil.debug("LayoutManager: layouts loaded successfully");
+				} else {
+					LogUtil.error("LayoutManager: layouts not loaded (" + e.error.message + ")");
+				}
+			});
+			loader.loadFromUrl(layoutUrl);
+		}
+		
+		public function saveLayoutsToFile():void {
+			var _fileRef:FileReference = new FileReference();
+			_fileRef.addEventListener(Event.COMPLETE, function(e:Event):void {
+				Alert.show(ResourceUtil.getInstance().getString('bbb.layout.save.complete'), "", Alert.OK, _canvas);
+			});
+			_fileRef.save(_layouts.toXml().toXMLString(), "layouts.xml");
+		}
+		
+		public function loadLayoutsFromFile():void {
+			var loader:LayoutLoader = new LayoutLoader();
+			loader.addEventListener(LayoutsLoadedEvent.LAYOUTS_LOADED_EVENT, function(e:LayoutsLoadedEvent):void {
+				if (e.success) {
+					_layouts = e.layouts;
+					
+					/*
+					 * \TODO why do I need to create a new Event for this?
+					 */
+					var layoutsLoaded:LayoutsLoadedEvent = new LayoutsLoadedEvent();
+					layoutsLoaded.layouts = _layouts;
+					_globalDispatcher.dispatchEvent(layoutsLoaded);
+					/*
+					 *	it will update the ComboBox label, and will go back to this class
+					 * 	to apply the default layout
+					 */
+					_globalDispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.APPLY_DEFAULT_LAYOUT_EVENT));
+					
+					Alert.show(ResourceUtil.getInstance().getString('bbb.layout.load.complete'), "", Alert.OK, _canvas);
+				} else
+					Alert.show(ResourceUtil.getInstance().getString('bbb.layout.load.failed'), "", Alert.OK, _canvas);
+			});
+			loader.loadFromLocalFile();
+		}
+		
+		public function addCurrentLayoutToList():void {
+			var remotePrefix:String = "[" + ResourceUtil.getInstance().getString('bbb.layout.combo.remote') + "] ";
+			// starts with
+			var isRemoteLayout:Boolean = (_currentLayout.name.indexOf(remotePrefix) == 0);
+			if (isRemoteLayout) {
+				// remove the remote prefix
+				_currentLayout.name = _currentLayout.name.substring(remotePrefix.length);
+				// if it's a remote custom layout, just remove the counter
+				if (_currentLayout.name.indexOf(ResourceUtil.getInstance().getString('bbb.layout.combo.customName')) == 0)
+					_currentLayout.name = ResourceUtil.getInstance().getString('bbb.layout.combo.customName');
+			}
+			
+			// only add a layout to the list if it's a custom layout
+			if (_currentLayout.name == ResourceUtil.getInstance().getString('bbb.layout.combo.customName')) {
+				_currentLayout.name += " " + (++_customLayoutsCount); 
+				_layouts.push(_currentLayout);
+				var layoutsLoaded:LayoutsLoadedEvent = new LayoutsLoadedEvent();
+				layoutsLoaded.layouts = _layouts;
+				_globalDispatcher.dispatchEvent(layoutsLoaded);
+				
+				var redefineLayout:RedefineLayoutEvent = new RedefineLayoutEvent();
+				redefineLayout.layout = _currentLayout;
+				// this is to force LayoutCombo to update the current label
+				redefineLayout.remote = true;
+				_globalDispatcher.dispatchEvent(redefineLayout);
+			}
+		}
+		
+		public function setCanvas(canvas:MDICanvas):void {
+			_canvas = canvas;
+			/*
+			 * it should be dispatched when the layouts get loaded, but
+			 * the view is not ready at that point to receive the layouts
+			 * and populate the ComboBox
+			 */
+			if (_layouts != null) {
+				var e:LayoutsLoadedEvent = new LayoutsLoadedEvent();
+				e.layouts = _layouts;
+				_globalDispatcher.dispatchEvent(e);
+			}
+
+			// this is to detect changes on the container
+			_canvas.windowManager.container.addEventListener(ResizeEvent.RESIZE, onContainerResized);
+//	        _canvas.windowManager.container.addEventListener(Event.ACTIVATE, onContainerActivated);
+//	        _canvas.windowManager.container.addEventListener(Event.DEACTIVATE, onContainerDeactivated);
+
+			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_RESIZE_END, onActionOverWindowFinished);
+			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_DRAG_END, onActionOverWindowFinished);
+			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_MINIMIZE, onActionOverWindowFinished);
+			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_MAXIMIZE, onActionOverWindowFinished);
+			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_RESTORE, onActionOverWindowFinished);
+			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_ADD, function(e:MDIManagerEvent):void {
+				checkPermissionsOverWindow(e.window);
+				applyLayout(_currentLayout);
+			});
+			
+			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_FOCUS_START, function(e:MDIManagerEvent):void {
+				OrderManager.getInstance().bringToFront(e.window);
+			});
+			for each (var window:MDIWindow in _canvas.windowManager.windowList.reverse()) {
+				OrderManager.getInstance().bringToFront(window);
+			}
+		}
+
+		public function applyDefaultLayout():void {
+			applyLayout(_layouts.getDefault());
+			sendLayoutUpdate(_currentLayout);
+		}
+		
+		public function lockLayout():void {
+			_locked = true;
+			LogUtil.debug("LayoutManager: layout locked by myself");
+			sendLayoutUpdate(_currentLayout);
+		}
+		
+		private function sendLayoutUpdate(layout:LayoutDefinition):void {
+			if (_locked && UserManager.getInstance().getConference().amIModerator()) {
+				LogUtil.debug("LayoutManager: sending layout to remotes");
+				var e:UpdateLayoutEvent = new UpdateLayoutEvent();
+				e.layout = layout;
+				_globalDispatcher.dispatchEvent(e);
+			}
+		}
+		
+		private function applyLayout(layout:LayoutDefinition):void {
+			_detectContainerChange = false;
+			if (layout != null)
+				layout.applyToCanvas(_canvas);
+			updateCurrentLayout(layout);
+			_detectContainerChange = true;
+		}
+
+		public function redefineLayout(e:RedefineLayoutEvent):void {
+			var layout:LayoutDefinition = e.layout;
+			applyLayout(layout);
+			if (!e.remote)
+				sendLayoutUpdate(layout);
+		}
+		
+		public function remoteLockLayout():void {
+			LogUtil.debug("LayoutManager: remote lock received");
+			_locked = true;
+			checkPermissionsOverWindow();
+		}
+		
+		public function remoteUnlockLayout():void {
+			LogUtil.debug("LayoutManager: remote unlock received");
+			_locked = false;
+			checkPermissionsOverWindow();
+		}
+		
+		private function checkPermissionsOverWindow(window:MDIWindow=null):void {
+			if (window != null) {
+				if (!UserManager.getInstance().getConference().amIModerator()
+						&& !LayoutDefinition.ignoreWindow(window)) {
+					window.draggable 
+							= window.resizable
+							= window.showControls
+							= !_locked;
+				}
+			} else {
+				for each (window in _canvas.windowManager.windowList) {
+					checkPermissionsOverWindow(window);
+				}
+			}
+		}
+		
+		private function onContainerResized(e:ResizeEvent):void {
+			/*
+			 *	the main canvas has been resized
+			 *	while the user is resizing the window, this event is dispatched 
+			 *	multiple times, so we use a timer to re-apply the current layout
+			 *	only once, when the user finished his action
+			 */
+			_applyCurrentLayoutTimer.reset();
+			_applyCurrentLayoutTimer.start();
+		}
+		
+//		private function onContainerActivated(e:Event):void {
+//			printSomething("onContainerActivated");
+//		}
+//
+//		private function onContainerDeactivated(e:Event = null):void {
+//			printSomething("onContainerDeactivated");
+//		}
+		
+		private function onActionOverWindowFinished(e:MDIManagerEvent):void {
+			if (LayoutDefinition.ignoreWindow(e.window))
+				return;
+				
+			checkPermissionsOverWindow(e.window);
+			if (_detectContainerChange) {
+				_globalDispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.INVALIDATE_LAYOUT_EVENT));
+				/*
+				 * 	some events related to animated actions must be delayed because if it's not the 
+				 * 	current layout doesn't get properly updated
+				 */
+				if (_eventsToDelay.indexOf(e.type) != -1) {
+					LogUtil.debug("LayoutManager: waiting the end of the animation to update the current layout");
+					_sendCurrentLayoutUpdateTimer.reset();
+					_sendCurrentLayoutUpdateTimer.start();
+				} else {
+					sendLayoutUpdate(updateCurrentLayout());
+				}
+			}
+		}
+		
+		private function updateCurrentLayout(layout:LayoutDefinition=null):LayoutDefinition {
+			_currentLayout = (layout != null? layout: LayoutDefinition.getLayout(_canvas, ResourceUtil.getInstance().getString('bbb.layout.combo.customName')));
+			return _currentLayout;
+		}
+		
+		/*
+		 * this is because a unique layout may have multiple definitions depending
+		 * on the role of the participant
+		 */ 
+		public function presenterChanged():void {
+			applyLayout(_currentLayout);
+		}
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/managers/OrderManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/managers/OrderManager.as
new file mode 100644
index 0000000000000000000000000000000000000000..f6470fd687d80d0dc0d7c00de2d73f6ed7a4d70d
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/managers/OrderManager.as
@@ -0,0 +1,110 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.modules.layout.managers
+{
+
+	import flash.utils.Dictionary;
+
+	import flexlib.mdi.containers.MDIWindow;
+
+	import org.bigbluebutton.common.LogUtil;
+	import org.bigbluebutton.modules.layout.model.LayoutDefinition;
+	import org.bigbluebutton.modules.layout.model.WindowLayout;
+
+	public class OrderManager {
+		private static var _instance:OrderManager = null;
+		private var _windowsOrder:Dictionary = new Dictionary();
+	
+		/**
+		 * This class is a singleton. Please initialize it using the getInstance() method.
+		 * 
+		 */		
+		public function OrderManager(enforcer:SingletonEnforcer) {
+			if (enforcer == null){
+				throw new Error("There can only be 1 OrderManager instance");
+			}
+			initialize();
+		}
+		
+		private function initialize():void{
+		}
+		
+		/**
+		 * Return the single instance of the UserManager class
+		 */
+		public static function getInstance():OrderManager{
+			if (_instance == null){
+				_instance = new OrderManager(new SingletonEnforcer());
+			}
+			return _instance;
+		}
+
+		public function bringToFront(window:MDIWindow):void {
+			if (LayoutDefinition.ignoreWindow(window))
+				return;
+			
+			var type:String = WindowLayout.getType(window);
+			var currentOrder:int = int.MAX_VALUE;
+			if (_windowsOrder.hasOwnProperty(type))
+				currentOrder = _windowsOrder[type].order;
+
+			for (var key:Object in _windowsOrder) {
+				var tmpOrder:int = _windowsOrder[key].order;
+				if (tmpOrder <= currentOrder)
+					_windowsOrder[key].order = tmpOrder + 1;
+//				LogUtil.debug("==========> " + key + " order: " + _windowsOrder[key].order);
+			}
+			_windowsOrder[type] = { order: 0 };
+			
+//			if (_windowsOrder.length > window.windowManager.windowList.length) {
+//				var openWindows:Array = new Array();
+//				for each (var tmp:MDIWindow in window.windowManager.windowList) {
+//					openWindows.push(WindowLayout.getType(tmp));
+//				}
+//				for (key in _windowsOrder) {
+//					if (openWindows.indexOf(key) == -1) {
+//						LogUtil.debug("Removing order for " + key);
+//						delete _windowsOrder[key];
+//					}
+//				}
+//			}
+//			LogUtil.debug("Manipulating " + type);
+//			for (key in _windowsOrder) {
+//				LogUtil.debug("=====> " + key + " order: " + _windowsOrder[key].order);
+//			}
+			
+//			window.windowManager.bringToFront(window);
+		}
+		
+		public function getOrderByType(type:String):int {
+			if (_windowsOrder.hasOwnProperty(type))
+				return _windowsOrder[type].order;
+			else
+				return -1;
+		}
+		
+		public function getOrderByRef(window:MDIWindow):int {
+			return getOrderByType(WindowLayout.getType(window));
+		}
+		
+	}
+}
+
+class SingletonEnforcer{}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/maps/LayoutEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/maps/LayoutEventMap.mxml
new file mode 100755
index 0000000000000000000000000000000000000000..97849f5acdb6502c4393862c9e604fec24bb91cf
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/maps/LayoutEventMap.mxml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+  Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+  This program 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; either version 2.1 of the License, or (at your option) any later
+  version.
+
+  BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+  Author: Felipe Cecagno <felipe@mconf.org>
+
+  $Id: $
+-->
+<EventMap xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="http://mate.asfusion.com/">
+	<mx:Script>
+		<![CDATA[
+			import mx.events.FlexEvent;
+
+			import org.bigbluebutton.main.events.MadePresenterEvent;
+			import org.bigbluebutton.modules.layout.events.ConnectionEvent;
+			import org.bigbluebutton.modules.layout.events.LayoutEvent;
+			import org.bigbluebutton.modules.layout.events.UpdateLayoutEvent;
+			import org.bigbluebutton.modules.layout.events.StartLayoutModuleEvent;
+			import org.bigbluebutton.modules.layout.events.ViewInitializedEvent;
+			import org.bigbluebutton.modules.layout.events.RedefineLayoutEvent;
+			import org.bigbluebutton.modules.layout.managers.LayoutManager;
+			import org.bigbluebutton.modules.layout.services.LayoutService;
+		]]>
+	</mx:Script>
+
+	<EventHandlers type="{FlexEvent.PREINITIALIZE}">
+		<ObjectBuilder generator="{LayoutEventMapDelegate}" constructorArguments="{scope.dispatcher}" />
+		<ObjectBuilder generator="{LayoutManager}" />
+	</EventHandlers>
+	
+	<EventHandlers type="{StartLayoutModuleEvent.START_LAYOUT_MODULE_EVENT}">        
+		<ObjectBuilder generator="{LayoutService}" constructorArguments="{event.attributes}" />
+   		<MethodInvoker generator="{LayoutEventMapDelegate}" method="startModule" arguments="{event.attributes}" />
+   		<MethodInvoker generator="{LayoutManager}" method="loadServerLayouts" arguments="{event.attributes.layoutConfig}" />
+    </EventHandlers>
+    
+	<EventHandlers type="{ViewInitializedEvent.VIEW_INITIALIZED_EVENT}">
+   		<MethodInvoker generator="{LayoutManager}" method="setCanvas" arguments="{event.canvas}" />
+   		<MethodInvoker generator="{LayoutService}" method="join" />
+    </EventHandlers>
+    
+    <EventHandlers type="{LayoutEvent.STOP_LAYOUT_MODULE_EVENT}">
+   		<MethodInvoker generator="{LayoutService}" method="leave" />
+   		<MethodInvoker generator="{LayoutEventMapDelegate}" method="stopModule" />
+    </EventHandlers>
+        
+    <EventHandlers type="{ConnectionEvent.CONNECT_EVENT}">
+   		<MethodInvoker generator="{LayoutService}" method="initLayout" arguments="{event.success}" />
+    </EventHandlers>
+    
+    <EventHandlers type="{LayoutEvent.APPLY_DEFAULT_LAYOUT_EVENT}">
+   		<MethodInvoker generator="{LayoutManager}" method="applyDefaultLayout" />
+    </EventHandlers>
+    
+    <EventHandlers type="{LayoutEvent.LOCK_LAYOUT_EVENT}">
+   		<MethodInvoker generator="{LayoutManager}" method="lockLayout" />
+    </EventHandlers>
+
+    <EventHandlers type="{LayoutEvent.UNLOCK_LAYOUT_EVENT}">
+   		<MethodInvoker generator="{LayoutService}" method="unlockLayout" />
+    </EventHandlers>
+
+    <EventHandlers type="{UpdateLayoutEvent.UPDATE_LAYOUT_EVENT}">
+   		<MethodInvoker generator="{LayoutService}" method="lockLayout" arguments="{event.layout}" />
+    </EventHandlers>
+    
+    <EventHandlers type="{RedefineLayoutEvent.REDEFINE_LAYOUT_EVENT}">
+   		<MethodInvoker generator="{LayoutManager}" method="redefineLayout" arguments="{event}" />
+    </EventHandlers>
+	
+    <EventHandlers type="{LayoutEvent.SAVE_LAYOUTS_EVENT}">
+   		<MethodInvoker generator="{LayoutManager}" method="saveLayoutsToFile" />
+    </EventHandlers>
+	
+    <EventHandlers type="{LayoutEvent.LOAD_LAYOUTS_EVENT}">
+   		<MethodInvoker generator="{LayoutManager}" method="loadLayoutsFromFile" />
+    </EventHandlers>
+	
+    <EventHandlers type="{LayoutEvent.ADD_CURRENT_LAYOUT_EVENT}">
+   		<MethodInvoker generator="{LayoutManager}" method="addCurrentLayoutToList" />
+    </EventHandlers>
+	
+    <EventHandlers type="{LayoutEvent.REMOTE_LOCK_LAYOUT_EVENT}">
+   		<MethodInvoker generator="{LayoutManager}" method="remoteLockLayout" />
+    </EventHandlers>
+	
+    <EventHandlers type="{LayoutEvent.REMOTE_UNLOCK_LAYOUT_EVENT}">
+   		<MethodInvoker generator="{LayoutManager}" method="remoteUnlockLayout" />
+    </EventHandlers>
+	
+    <EventHandlers type="{MadePresenterEvent.SWITCH_TO_VIEWER_MODE}">
+   		<MethodInvoker generator="{LayoutManager}" method="presenterChanged" />
+    </EventHandlers>
+
+    <EventHandlers type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}">
+   		<MethodInvoker generator="{LayoutManager}" method="presenterChanged" />
+    </EventHandlers>
+
+    <!-- EventHandlers type="{FlexEvent.CREATION_COMPLETE}">        
+   		<MethodInvoker generator="{LayoutManager}" method="printSomething" arguments="{FlexEvent.CREATION_COMPLETE}" />
+    </EventHandlers>
+	
+    <EventHandlers type="{FlexEvent.CONTENT_CREATION_COMPLETE}">        
+   		<MethodInvoker generator="{LayoutManager}" method="printSomething" arguments="{FlexEvent.CONTENT_CREATION_COMPLETE}" />
+    </EventHandlers>
+	
+    <EventHandlers type="{FlexEvent.INIT_COMPLETE}">        
+   		<MethodInvoker generator="{LayoutManager}" method="printSomething" arguments="{FlexEvent.INIT_COMPLETE}" />
+    </EventHandlers-->
+	
+</EventMap>
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/maps/LayoutEventMapDelegate.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/maps/LayoutEventMapDelegate.mxml
new file mode 100755
index 0000000000000000000000000000000000000000..5be9e3935c03f025410247ad7a50bdd57a7b0913
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/maps/LayoutEventMapDelegate.mxml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+  Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+  This program 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; either version 2.1 of the License, or (at your option) any later
+  version.
+
+  BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+  Author: Felipe Cecagno <felipe@mconf.org>
+
+  $Id: $
+-->
+<EventMap xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="http://mate.asfusion.com/">
+	<mx:Script>
+		<![CDATA[
+			import com.asfusion.mate.events.Dispatcher;
+
+			import org.bigbluebutton.common.LogUtil;
+			import org.bigbluebutton.common.events.ToolbarButtonEvent;
+			import org.bigbluebutton.modules.layout.views.ToolbarComponent;
+			
+			private var _attributes:Object;
+			private var _globalDispatcher:Dispatcher = new Dispatcher();
+			
+			public function stopModule():void {
+			}
+			
+			public function startModule(attributes:Object):void {
+				_attributes = attributes;
+				
+				var layoutComponent:ToolbarComponent = new ToolbarComponent();
+				// using the negation will keep it enabled if the property is not there
+				layoutComponent.enableEdit = !(_attributes.enableEdit == "false");
+				
+				var event:ToolbarButtonEvent = new ToolbarButtonEvent(ToolbarButtonEvent.ADD);
+				event.button = layoutComponent;
+				event.location = ToolbarButtonEvent.BOTTOM_TOOLBAR;
+				_globalDispatcher.dispatchEvent(event);
+			}
+		]]>
+	</mx:Script>
+</EventMap>
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutDefinition.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutDefinition.as
new file mode 100644
index 0000000000000000000000000000000000000000..7d40db860ff10e11676790dacd07a5df574bffe9
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutDefinition.as
@@ -0,0 +1,220 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.modules.layout.model {
+
+	public class LayoutDefinition {
+
+		import flash.utils.Dictionary;
+		import flexlib.mdi.containers.MDICanvas;
+		import flexlib.mdi.containers.MDIWindow;
+		
+		import org.bigbluebutton.common.LogUtil;
+		import org.bigbluebutton.common.Role;
+		import org.bigbluebutton.core.managers.UserManager;
+		import org.bigbluebutton.modules.layout.managers.OrderManager;
+		
+		[Bindable] public var name:String;
+		// default is a reserved word in actionscript
+		[Bindable] public var defaultLayout:Boolean = false;
+		private var _windows:Dictionary = new Dictionary();
+		
+		static private var _ignoredWindows:Array = new Array("PublishWindow", 
+				"VideoWindow", "DesktopPublishWindow", "DesktopViewWindow",
+				"LogWindow");
+		static private var _roles:Array = new Array(Role.VIEWER, Role.MODERATOR, Role.PRESENTER);
+		
+		public function LayoutDefinition() {
+			
+		}
+		
+		private function loadLayout(vxml:XML):void {
+			if (vxml.@name != undefined) {
+				name = vxml.@name.toString();
+			}
+			if (vxml.@default != undefined) {
+				defaultLayout = (vxml.@default.toString().toUpperCase() == "TRUE") ? true : false;
+			}
+			var role:String = Role.VIEWER;
+			if (vxml.@role != undefined && _roles.indexOf(vxml.@role.toString().toUpperCase()) != -1) {
+				role = vxml.@role.toString().toUpperCase();
+			}
+			if (!_windows.hasOwnProperty(role))
+				_windows[role] = new Dictionary();
+			for each (var n:XML in vxml.window) {
+				var window:WindowLayout = new WindowLayout();
+				window.load(n);
+				_windows[role][window.name] = window;
+			}
+		}
+		
+		public function load(vxml:XML):void {
+			if (vxml == null)
+				return;
+			
+			if (vxml.name().localName == "layout")
+				loadLayout(vxml);
+			else if (vxml.name().localName == "layout-block") {
+				for each (var tmp:XML in vxml.layout)
+					loadLayout(tmp);
+			}
+		}
+
+		private function get myLayout():Dictionary {
+			var hasViewerLayout:Boolean = _windows.hasOwnProperty(Role.VIEWER);
+			var hasModeratorLayout:Boolean = _windows.hasOwnProperty(Role.MODERATOR);
+			var hasPresenterLayout:Boolean = _windows.hasOwnProperty(Role.PRESENTER);
+			
+			if (UserManager.getInstance().getConference().amIPresenter() && hasPresenterLayout)
+				return _windows[Role.PRESENTER];
+			else if (UserManager.getInstance().getConference().amIModerator() && hasModeratorLayout)
+				return _windows[Role.MODERATOR];
+			else if (hasViewerLayout) 
+				return _windows[Role.VIEWER];
+			else if (hasModeratorLayout)
+				return _windows[Role.MODERATOR];
+			else if (hasPresenterLayout)
+				return _windows[Role.PRESENTER];
+			else {
+				LogUtil.error("There's no layout that fits the participants profile");
+				return null;
+			}
+		}
+		
+		public function windowLayout(name:String):WindowLayout {
+			return myLayout[name];
+		}
+		
+		private function windowsToXml(windows:Dictionary):XML {
+			var xml:XML = <layout/>;
+			xml.@name = name;
+			if (defaultLayout)
+				xml.@default = true;
+			for each (var value:WindowLayout in windows) {
+				xml.appendChild(value.toXml());
+			}
+			return xml;
+		}
+		
+		public function toXml():XML {
+			var xml:XML = <layout-block/>;
+			var tmp:XML;
+			for each (var value:String in _roles) {
+				if (_windows.hasOwnProperty(value)) {
+					tmp = windowsToXml(_windows[value]);
+					if (value != Role.VIEWER)
+						tmp.@role = value;
+					xml.appendChild(tmp);
+				}
+			}
+			return xml;
+		}
+		
+		/*
+		 * 0 if there's no order
+		 * 1 if "a" should appears after "b"
+		 * -1 if "a" should appears before "b"
+		 */
+		private function sortWindows(a:Object, b:Object):int {
+			// ignored windows are positioned in front
+			if (a.ignored && b.ignored) return 0;
+			if (a.ignored) return 1;
+			if (b.ignored) return -1;
+			// then comes the windows that has no layout definition
+			if (!a.hasLayoutDefinition && !b.hasLayoutDefinition) return 0;
+			if (!a.hasLayoutDefinition) return 1;
+			if (!b.hasLayoutDefinition) return -1;
+			// then the focus order is used to sort
+			if (a.order == b.order) return 0;
+			if (a.order == -1) return 1;
+			if (b.order == -1) return -1;
+			return (a.order < b.order? 1: -1);
+		}
+		
+		private function adjustWindowsOrder(canvas:MDICanvas):void {
+			var orderedList:Array = new Array();
+			var type:String;
+			var order:int;
+			var ignored:Boolean;
+			var hasLayoutDefinition:Boolean;
+			
+//			LogUtil.debug("=> Before sort");
+			for each (var window:MDIWindow in canvas.windowManager.windowList) {
+				type = WindowLayout.getType(window);
+				hasLayoutDefinition = myLayout.hasOwnProperty(type);
+				if (hasLayoutDefinition)
+					order = myLayout[type].order;
+				else
+					order = -1;
+				ignored = ignoreWindowByType(type);
+				var item:Object = { window:window, order:order, type:type, ignored:ignored, hasLayoutDefinition:hasLayoutDefinition };
+				orderedList.push(item);
+//				LogUtil.debug("===> type: " + item.type + " ignored? " + item.ignored + " hasLayoutDefinition? " + item.hasLayoutDefinition + " order? " + item.order);
+			}
+			orderedList.sort(this.sortWindows);
+//			LogUtil.debug("=> After sort");
+			for each (var obj:Object in orderedList) {
+//				LogUtil.debug("===> type: " + obj.type + " ignored? " + obj.ignored + " hasLayoutDefinition? " + obj.hasLayoutDefinition + " order? " + obj.order);
+				if (!obj.ignored)
+					OrderManager.getInstance().bringToFront(obj.window);
+				canvas.windowManager.bringToFront(obj.window);
+			}
+		}
+		
+		public function applyToCanvas(canvas:MDICanvas):void {
+			if (canvas == null)
+				return;
+
+			adjustWindowsOrder(canvas);
+
+			for each (var window:MDIWindow in canvas.windowManager.windowList) {
+				applyToWindow(canvas, window);
+			}
+		}
+		
+		public function applyToWindow(canvas:MDICanvas, window:MDIWindow, type:String=null):void {
+			if (type == null)
+				type = WindowLayout.getType(window);
+
+			if (!ignoreWindowByType(type))
+				WindowLayout.setLayout(canvas, window, myLayout[type]);
+		}
+		
+		static private function ignoreWindowByType(type:String):Boolean {
+			return (_ignoredWindows.indexOf(type) != -1);
+		}
+		
+		static public function ignoreWindow(window:MDIWindow):Boolean {
+			var type:String = WindowLayout.getType(window);
+			return ignoreWindowByType(type);
+		}
+		
+		static public function getLayout(canvas:MDICanvas, name:String):LayoutDefinition {
+			var layoutDefinition:LayoutDefinition = new LayoutDefinition();
+			layoutDefinition.name = name;
+			layoutDefinition._windows[Role.VIEWER] = new Dictionary();
+			for each (var window:MDIWindow in canvas.windowManager.windowList) {
+				var layout:WindowLayout = WindowLayout.getLayout(canvas, window);
+				if (!ignoreWindowByType(layout.name))
+					layoutDefinition._windows[Role.VIEWER][layout.name] = layout;
+			}
+			return layoutDefinition;
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutDefinitionFile.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutDefinitionFile.as
new file mode 100644
index 0000000000000000000000000000000000000000..a5ade46218d614879662743c224760bb304057e5
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutDefinitionFile.as
@@ -0,0 +1,80 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.modules.layout.model
+{
+	import flash.events.EventDispatcher;
+
+	import org.bigbluebutton.common.LogUtil;
+	import org.bigbluebutton.core.EventBroadcaster;
+	import org.bigbluebutton.core.model.Config;
+	import org.bigbluebutton.modules.layout.events.LayoutsLoadedEvent;
+	import org.bigbluebutton.modules.layout.model.LayoutDefinition;
+	
+	public class LayoutDefinitionFile extends EventDispatcher {
+		private var _layouts:Array = new Array();
+		
+		public function get list():Array {
+			return _layouts;
+		}
+		
+		public function pushXml(xml:XML):void {
+			if (xml.@name == undefined)
+				return;
+				
+			var layoutDefinition:LayoutDefinition = null;
+			for each (var layout:LayoutDefinition in _layouts) {
+				if (layout.name == xml.@name) {
+					layoutDefinition = layout;
+					break; 
+				}
+			}
+			
+			if (layoutDefinition == null) {
+				layoutDefinition = new LayoutDefinition();
+				layoutDefinition.load(xml);
+				_layouts.push(layoutDefinition);
+			} else {
+				layoutDefinition.load(xml);
+			}
+		}
+		
+		public function push(layoutDefinition:LayoutDefinition):void {
+			_layouts.push(layoutDefinition);
+		}
+		
+		public function getDefault():LayoutDefinition {
+			for each (var value:LayoutDefinition in _layouts) {
+				if (value.defaultLayout)
+					return value;
+			}
+			return null;
+		}
+		
+		public function toXml():XML {
+			var xml:XML = <layouts/>;
+			for each (var layoutDefinition:LayoutDefinition in _layouts) {
+				for each (var value:XML in layoutDefinition.toXml()) {
+					xml.appendChild(value);
+				}
+			}
+			return xml;
+		}
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutLoader.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutLoader.as
new file mode 100644
index 0000000000000000000000000000000000000000..de96f8a05db7045e8081c5e09a50033ed4b0479e
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutLoader.as
@@ -0,0 +1,111 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.modules.layout.model
+{
+	import flash.events.EventDispatcher;
+	import flash.events.Event;
+	import flash.events.ProgressEvent;
+	import flash.events.IOErrorEvent;
+	import flash.events.SecurityErrorEvent;
+	import flash.net.FileReference;
+
+	import flash.net.URLLoader;
+	import flash.net.URLRequest;
+	
+	import org.bigbluebutton.common.LogUtil;
+	import org.bigbluebutton.core.EventBroadcaster;
+	import org.bigbluebutton.core.model.Config;
+	import org.bigbluebutton.modules.layout.events.LayoutsLoadedEvent;
+	import org.bigbluebutton.modules.layout.model.LayoutDefinition;
+	import org.bigbluebutton.util.i18n.ResourceUtil;
+	
+	public class LayoutLoader extends EventDispatcher {
+		private var _fileRef:FileReference;
+		
+		public function loadFromUrl(layoutUrl:String):void {
+			var urlLoader:URLLoader = new URLLoader();
+			urlLoader.addEventListener(Event.COMPLETE, onComplete);
+			urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
+			var date:Date = new Date();
+			try {
+				urlLoader.load(new URLRequest(layoutUrl + "?a=" + date.time));
+			} catch (e:Error) {
+				LogUtil.debug("LayoutsLoader: exception while loading the layout definition file (" + e + ")");
+			}
+		}
+		
+		public function loadFromLocalFile():void {
+			_fileRef = new FileReference();
+			_fileRef.addEventListener(Event.SELECT, onFileSelected); 
+			_fileRef.addEventListener(Event.CANCEL, onCancel); 
+			_fileRef.addEventListener(IOErrorEvent.IO_ERROR, onIOError); 
+			_fileRef.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
+			_fileRef.browse();
+		}
+		
+		private function onComplete(evt:Event):void {
+			LogUtil.debug("LayoutsLoader: completed, parsing...");
+			var layouts:LayoutDefinitionFile = new LayoutDefinitionFile();
+			var event:LayoutsLoadedEvent = new LayoutsLoadedEvent();
+			try {
+				var data:XML = new XML(evt.target.data);
+				for each (var n:XML in data.layout) {
+					layouts.pushXml(n);
+				}
+				event.layouts = layouts;
+				event.success = true;
+				dispatchEvent(event);
+			} catch (error:TypeError) {
+				event.success = false;
+				event.error = new TypeError("Failed to parse the XML: " + error.message);
+				dispatchEvent(event);
+			}
+		}
+		
+		private function onFileSelected(evt:Event):void { 
+			LogUtil.debug("LayoutsLoader: file selected");
+			_fileRef.addEventListener(ProgressEvent.PROGRESS, onProgress);
+			_fileRef.addEventListener(Event.COMPLETE, onComplete);
+			_fileRef.load();
+		} 
+        
+		private function onProgress(evt:ProgressEvent):void {
+			LogUtil.debug("LayoutsLoader: loaded " + evt.bytesLoaded + " of " + evt.bytesTotal + " bytes"); 
+		} 
+
+		private function onCancel(evt:Event):void {
+			LogUtil.debug("LayoutsLoader: the browse request was canceled by the user"); 
+		} 
+		
+		private function onIOError(evt:IOErrorEvent):void {
+			var event:LayoutsLoadedEvent = new LayoutsLoadedEvent();
+			event.success = false;
+			event.error = new TypeError(ResourceUtil.getInstance().getString('bbb.layout.load.ioError'));
+			dispatchEvent(event);
+		} 
+
+		private function onSecurityError(evt:Event):void { 
+			var event:LayoutsLoadedEvent = new LayoutsLoadedEvent();
+			event.success = false;
+			event.error = new TypeError(ResourceUtil.getInstance().getString('bbb.layout.load.securityError'));
+			dispatchEvent(event);
+		}
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/WindowLayout.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/WindowLayout.as
new file mode 100644
index 0000000000000000000000000000000000000000..2fc4c5750cd695be3476c14d4b518cf987d09012
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/WindowLayout.as
@@ -0,0 +1,230 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.modules.layout.model {
+
+	public class WindowLayout {
+
+		import flexlib.mdi.containers.MDICanvas;
+		import flexlib.mdi.containers.MDIWindow;
+
+		import mx.effects.Fade;
+		import mx.effects.Move;
+		import mx.effects.Parallel;
+		import mx.effects.Resize;
+		import mx.events.EffectEvent;
+
+		import flash.display.DisplayObject;
+		import flash.display.DisplayObjectContainer;
+		import flash.utils.Dictionary;
+		import flash.utils.getQualifiedClassName;
+		import flash.utils.Timer;
+		import flash.events.TimerEvent;
+		import org.bigbluebutton.common.LogUtil;
+		import org.bigbluebutton.modules.layout.managers.OrderManager;
+
+		[Bindable] public var name:String;
+		[Bindable] public var width:Number;
+		[Bindable] public var height:Number;
+		[Bindable] public var x:Number;
+		[Bindable] public var y:Number;
+		[Bindable] public var minimized:Boolean = false;
+		[Bindable] public var maximized:Boolean = false;
+		[Bindable] public var hidden:Boolean = false;
+		[Bindable] public var order:int = -1;
+		
+
+		static private var EVENT_DURATION:int = 500;
+
+		public function load(vxml:XML):void {
+			if (vxml != null) {
+				if (vxml.@name != undefined) {
+					name = vxml.@name.toString();
+				}
+				if (vxml.@width != undefined) {
+					width = Number(vxml.@width);
+				}
+				if (vxml.@height != undefined) {
+					height = Number(vxml.@height);
+				}
+				if (vxml.@x != undefined) {
+					x = Number(vxml.@x);
+				}
+				if (vxml.@y != undefined) {
+					y = Number(vxml.@y);
+				}
+				if (vxml.@minimized != undefined) {
+					minimized = (vxml.@minimized.toString().toUpperCase() == "TRUE") ? true : false;
+				}
+				if (vxml.@maximized != undefined) {
+					maximized = (vxml.@maximized.toString().toUpperCase() == "TRUE") ? true : false;
+				}
+				if (vxml.@hidden != undefined) {
+					hidden = (vxml.@hidden.toString().toUpperCase() == "TRUE") ? true : false;
+				}
+				if (vxml.@order != undefined) {
+					order = int(vxml.@order);
+				}
+			}
+		}
+		
+		static public function getLayout(canvas:MDICanvas, window:MDIWindow):WindowLayout {
+			var layout:WindowLayout = new WindowLayout();
+			layout.name = getType(window);
+			layout.width = window.width / canvas.width;
+			layout.height = window.height / canvas.height;
+			layout.x = window.x / canvas.width;
+			layout.y = window.y / canvas.height;
+			layout.minimized = window.minimized;
+			layout.maximized = window.maximized;
+			layout.hidden = !window.visible;
+			layout.order = OrderManager.getInstance().getOrderByRef(window);
+			return layout;
+		}
+		
+		static public function setLayout(canvas:MDICanvas, window:MDIWindow, layout:WindowLayout):void {
+			if (layout == null) return;
+			layout.applyToWindow(canvas, window);
+		}
+		
+		private var _delayedEffects:Array = new Array();
+		private function delayEffect(canvas:MDICanvas, window:MDIWindow):void {
+			var obj:Object = {canvas:canvas, window:window};
+			_delayedEffects.push(obj);
+			var timer:Timer = new Timer(150,1);
+			timer.addEventListener(TimerEvent.TIMER, onTimerComplete);
+			timer.start();
+		}
+		
+		private function onTimerComplete(event:TimerEvent = null):void {
+			var obj:Object = _delayedEffects.pop();
+			applyToWindow(obj.canvas, obj.window);
+		}
+		
+		public function applyToWindow(canvas:MDICanvas, window:MDIWindow):void {
+			var effect:Parallel = new Parallel();
+			effect.duration = EVENT_DURATION;
+			effect.target = window;
+			
+			if (this.minimized) {
+				if (!window.minimized) window.minimize();
+			} else if (this.maximized) {
+				if (!window.maximized) window.maximize();
+			} else if (window.minimized && !this.minimized && !this.hidden) {
+				window.unMinimize();
+				delayEffect(canvas, window);
+				return;
+			} else if (window.maximized && !this.maximized && !this.hidden) {
+				window.maximizeRestore();
+				delayEffect(canvas, window);
+				return;
+			} else {
+				if (!this.hidden) {
+					var newWidth:int = int(this.width * canvas.width);
+					var newHeight:int = int(this.height * canvas.height);
+					var newX:int = int(this.x * canvas.width);
+					var newY:int = int(this.y * canvas.height);
+					
+					if (newX != window.x || newY != window.y) {
+						var mover:Move = new Move();
+						mover.xTo = newX;
+						mover.yTo = newY;
+						effect.addChild(mover);
+					}
+					
+					if (newWidth != window.width || newHeight != window.height) {
+						var resizer:Resize = new Resize();
+						resizer.widthTo = newWidth;
+						resizer.heightTo = newHeight;
+						effect.addChild(resizer)
+					}
+				}
+			}
+			
+			var layoutHidden:Boolean = this.hidden;
+//			var windowVisible:Boolean = (window.alpha == 1);
+			var windowVisible:Boolean = window.visible;
+			if (windowVisible == layoutHidden) {
+				var fader:Fade = new Fade();
+				fader.alphaFrom = (layoutHidden? 1: 0);
+				fader.alphaTo = (layoutHidden? 0: 1);
+				fader.addEventListener(EffectEvent.EFFECT_START, function(e:EffectEvent):void {
+					if (!windowVisible)
+						window.enabled = window.visible = true;
+				});
+				fader.addEventListener(EffectEvent.EFFECT_END, function(e:EffectEvent):void {
+					if (windowVisible)
+						window.enabled = window.visible = false;
+				});
+				effect.addChild(fader);
+			}
+			
+			if (effect.children.length > 0)
+				effect.play();
+		}
+		
+		static public function getType(obj:Object):String {
+			var qualifiedClass:String = String(getQualifiedClassName(obj));
+			var pattern:RegExp = /(\w+)::(\w+)/g;
+			if (qualifiedClass.match(pattern)) {
+				return qualifiedClass.split("::")[1];
+			} else { 
+				return String(Object).substr(String(Object).lastIndexOf(".") + 1).match(/[a-zA-Z]+/).join();
+			}
+		}
+		
+		public function toAbsoluteXml(canvas:MDICanvas):XML {
+			var xml:XML = <window/>;
+			xml.@name = name;
+			if (minimized)
+				xml.@minimized = true;
+			else if (maximized)
+				xml.@maximized = true;
+			else if (hidden)
+				xml.@hidden = true;
+			else {
+				xml.@width = int(width * canvas.width);
+				xml.@height = int(height * canvas.height);
+				xml.@x = int(x * canvas.width);
+				xml.@y = int(y * canvas.height);
+			}
+			xml.@order = order;
+			return xml;
+		}
+		
+		public function toXml():XML {
+			var xml:XML = <window/>;
+			xml.@name = name;
+			if (minimized)
+				xml.@minimized = true;
+			else if (maximized)
+				xml.@maximized = true;
+			else if (hidden)
+				xml.@hidden = true;
+			else {
+				xml.@width = width;
+				xml.@height = height;
+				xml.@x = x;
+				xml.@y = y;
+			}
+			xml.@order = order;
+			return xml;			
+		}  
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/services/LayoutService.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/services/LayoutService.as
new file mode 100755
index 0000000000000000000000000000000000000000..7ffbac0ff1524b7112fd9d4692e3fce3c5a799e6
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/services/LayoutService.as
@@ -0,0 +1,57 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.modules.layout.services
+{
+	import flash.events.IEventDispatcher;
+	
+	import org.bigbluebutton.modules.layout.model.LayoutDefinition;
+	
+	public class LayoutService
+	{
+		private var _attributes:Object;
+		private var _layoutSOService:LayoutSharedObjectService;
+		
+		public function LayoutService(attributes:Object) {
+			_attributes = attributes;
+		}
+		
+		public function join():void {
+			_layoutSOService = new LayoutSharedObjectService(_attributes.connection);
+			_layoutSOService.join(_attributes.uri + "/" + _attributes.room);
+		}
+		
+		public function leave():void {
+			_layoutSOService.leave();
+		}
+		
+		public function initLayout(success:Boolean):void {
+			if (success)
+				_layoutSOService.initLayout();
+		}
+		
+		public function lockLayout(layout:LayoutDefinition):void {
+			_layoutSOService.lockLayout(layout);
+		}
+		
+		public function unlockLayout():void {
+			_layoutSOService.unlockLayout();
+		}
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/services/LayoutSharedObjectService.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/services/LayoutSharedObjectService.as
new file mode 100755
index 0000000000000000000000000000000000000000..7e267ce26dee2337a5b57398afb97d11a0abdbd5
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/services/LayoutSharedObjectService.as
@@ -0,0 +1,203 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program 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; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Author: Felipe Cecagno <felipe@mconf.org>
+ */
+package org.bigbluebutton.modules.layout.services
+{
+	import com.asfusion.mate.events.Dispatcher;
+	
+	import flash.events.AsyncErrorEvent;
+	import flash.events.IEventDispatcher;
+	import flash.events.NetStatusEvent;
+	import flash.events.SyncEvent;
+	import flash.events.TimerEvent;
+	import flash.net.NetConnection;
+	import flash.net.Responder;
+	import flash.net.SharedObject;
+	import flash.utils.Timer;
+	
+	import mx.controls.Alert;
+	
+	import org.bigbluebutton.common.LogUtil;
+	import org.bigbluebutton.core.managers.UserManager;
+	import org.bigbluebutton.modules.layout.events.ConnectionEvent;
+	import org.bigbluebutton.modules.layout.events.LayoutEvent;
+	import org.bigbluebutton.modules.layout.events.RedefineLayoutEvent;
+	import org.bigbluebutton.modules.layout.model.LayoutDefinition;
+	import org.bigbluebutton.util.i18n.ResourceUtil;
+
+	public class LayoutSharedObjectService
+	{
+		public static const NAME:String = "LayoutSharedObjectService";
+		
+		private var _layoutSO:SharedObject;
+		private var _connection:NetConnection;
+		private var _dispatcher:Dispatcher;
+		private var _locked:Boolean = false;
+		/*
+		 * the application of the first layout should be delayed to avoid
+		 * strange movements of the windows before set the correct position
+		 */
+		private var _applyFirstLayoutTimer:Timer = new Timer(750,1);
+		
+		public function LayoutSharedObjectService(connection:NetConnection)
+		{
+			_connection = connection;
+			_dispatcher = new Dispatcher();
+		}
+						
+	    public function join(uri:String):void
+		{
+			_layoutSO = SharedObject.getRemote("layoutSO", uri, false);
+			_layoutSO.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
+			_layoutSO.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
+			_layoutSO.addEventListener(SyncEvent.SYNC, sharedObjectSyncHandler);	
+			_layoutSO.client = this;
+			_layoutSO.connect(_connection);					
+		}
+		
+	    public function leave():void
+	    {
+	    	if (_layoutSO != null) {
+	    		_layoutSO.close();
+	    	}
+	    }
+
+		private function netStatusHandler(event:NetStatusEvent):void
+		{
+			var statusCode:String = event.info.code;
+			var connEvent:ConnectionEvent = new ConnectionEvent(ConnectionEvent.CONNECT_EVENT);
+			
+			switch ( statusCode ) 
+			{
+				case "NetConnection.Connect.Success":
+					connEvent.success = true;
+					break;
+				default:
+					connEvent.success = false;
+				   break;
+			}
+			_dispatcher.dispatchEvent(connEvent);
+		}
+		
+		public function initLayout():void {
+			var nc:NetConnection = _connection;
+			nc.call(
+				"layout.init",
+				new Responder(
+					function(result:Object):void {
+						_applyFirstLayoutTimer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void {
+							onReceivedFirstLayout(result);
+						});
+						_applyFirstLayoutTimer.start();
+					},
+					function(status:Object):void {
+						LogUtil.error("LayoutSharedObjectService:initLayout - An error occurred"); 
+						for (var x:Object in status) { 
+							LogUtil.error(x + " : " + status[x]); 
+						} 
+					}
+				)
+			);
+		}
+		
+		private function onReceivedFirstLayout(result:Object):void {
+			LogUtil.debug("LayoutService: handling the first layout"); 
+			var locked:Boolean = result[0];
+			var userId:int = result[1];
+			var layout:String = result[2];
+			if (locked)
+				remoteUpdateLayout(locked, userId, layout);
+			else
+				_dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.APPLY_DEFAULT_LAYOUT_EVENT));
+		}
+		
+		public function lockLayout(layout:LayoutDefinition):void {
+			var nc:NetConnection = _connection;
+			nc.call(
+				"layout.lock",
+				new Responder(
+					function(result:Object):void {
+					},
+					function(status:Object):void {
+						LogUtil.error("LayoutSharedObjectService:lockLayout - An error occurred"); 
+						for (var x:Object in status) { 
+							LogUtil.error(x + " : " + status[x]); 
+						} 
+					}
+				),
+				UserManager.getInstance().getConference().getMyUserId(),
+				layout.toXml().toXMLString()
+			);
+		}
+		
+		public function unlockLayout():void {
+			var nc:NetConnection = _connection;
+			nc.call(
+				"layout.unlock",
+				new Responder(
+					function(result:Object):void {
+					},
+					function(status:Object):void {
+						LogUtil.error("LayoutSharedObjectService:unlockLayout - An error occurred"); 
+						for (var x:Object in status) { 
+							LogUtil.error(x + " : " + status[x]); 
+						} 
+					}
+				)
+			);
+		}
+
+		public function remoteUpdateLayout(locked:Boolean, userId:int, layout:String):void {
+			var dispatchedByMe:Boolean = UserManager.getInstance().getConference().amIThisUser(userId);
+
+			LogUtil.debug("LayoutService: received a remote update" + (locked? " from " + (dispatchedByMe? "myself": "a remote user"): ""));
+			LogUtil.debug("Locked? " + (locked? "yes": "no"));
+			
+			if (!_locked && locked) {
+				_dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.REMOTE_LOCK_LAYOUT_EVENT));
+			} else if (_locked && !locked) {
+				_dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.REMOTE_UNLOCK_LAYOUT_EVENT));
+			}
+			
+			if (locked && !dispatchedByMe) {
+				LogUtil.debug("LayoutService: handling remote layout");
+				LogUtil.debug(layout);
+				var layoutDefinition:LayoutDefinition = new LayoutDefinition();
+				layoutDefinition.load(new XML(layout));
+				layoutDefinition.name = "[" + ResourceUtil.getInstance().getString('bbb.layout.combo.remote') + "] " + layoutDefinition.name;  
+				var redefineLayout:RedefineLayoutEvent = new RedefineLayoutEvent();
+				redefineLayout.layout = layoutDefinition;
+				redefineLayout.remote = true;
+				_dispatcher.dispatchEvent(redefineLayout);
+			}
+			_locked = locked;
+		}
+		
+		private function asyncErrorHandler(event:AsyncErrorEvent):void {
+			LogUtil.debug("LayoutService: layoutSO asynchronous error (" + event + ")");
+		}
+		
+		private function sharedObjectSyncHandler(event:SyncEvent):void {
+			LogUtil.debug("LayoutService: layoutSO connection established");
+			var connEvent:ConnectionEvent = new ConnectionEvent(ConnectionEvent.CONNECT_EVENT);	
+			connEvent.success = true;
+			_dispatcher.dispatchEvent(connEvent);
+		}
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/AddButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/AddButton.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..6f00a98358747b204504c5560c220fbb2ca7b376
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/AddButton.mxml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+  Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+  This program 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; either version 2.1 of the License, or (at your option) any later
+  version.
+
+  BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+  Author: Felipe Cecagno <felipe@mconf.org>
+
+  $Id: $
+-->
+<views:LayoutButton xmlns:mx="http://www.adobe.com/2006/mxml" 
+		   creationComplete="init()" 
+		   xmlns:mate="http://mate.asfusion.com/"
+		   xmlns:views="org.bigbluebutton.modules.layout.views.*"
+		   toolTip="{ResourceUtil.getInstance().getString('bbb.layout.addButton.toolTip')}"
+		   icon="{icon_add}"
+		   click="onClick(event)"
+		   enabled="{UserManager.getInstance().getConference().amIModerator()}">
+	
+	<mx:Script>
+		<![CDATA[
+			import com.asfusion.mate.events.Dispatcher;
+
+			import flash.events.Event;
+			
+			import org.bigbluebutton.common.Images;
+			import org.bigbluebutton.common.LogUtil;
+			import org.bigbluebutton.core.managers.UserManager;
+			import org.bigbluebutton.util.i18n.ResourceUtil;
+			import org.bigbluebutton.modules.layout.events.LayoutEvent;
+
+			private var _dispatcher:Dispatcher = new Dispatcher();
+			private var _images:Images = new Images();
+			[Bindable] private var icon_add:Class = _images.add;
+			
+			private function init():void {
+			}
+			
+			private function onClick(e:Event):void {
+				_dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.ADD_CURRENT_LAYOUT_EVENT));
+			}
+			
+		]]>
+	</mx:Script>
+</views:LayoutButton>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LayoutButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LayoutButton.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..ce2398d3285eb2703fa073895e6fff83aa5c04fd
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LayoutButton.mxml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+  Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+  This program 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; either version 2.1 of the License, or (at your option) any later
+  version.
+
+  BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+  Author: Felipe Cecagno <felipe@mconf.org>
+
+  $Id: $
+-->
+<mx:Button xmlns:mx="http://www.adobe.com/2006/mxml" 
+		   xmlns:mate="http://mate.asfusion.com/"
+		   width="{BUTTON_SIZE}"
+		   height="{BUTTON_SIZE}">
+	
+	<mx:Script>
+		<![CDATA[
+			import mx.controls.Button;
+
+			static public const BUTTON_SIZE:int = 20;
+		]]>
+	</mx:Script>
+</mx:Button>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LayoutsCombo.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LayoutsCombo.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..33c44e17d2ed847837da5bca8515453ecc3d4720
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LayoutsCombo.mxml
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+  Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+  This program 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; either version 2.1 of the License, or (at your option) any later
+  version.
+
+  BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+  Author: Felipe Cecagno <felipe@mconf.org>
+
+  $Id: $
+-->
+<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml" 
+			creationComplete="init()" 
+			xmlns:mate="http://mate.asfusion.com/"
+			toolTip="{ResourceUtil.getInstance().getString('bbb.layout.combo.toolTip')}"
+			prompt="{ResourceUtil.getInstance().getString('bbb.layout.combo.prompt')}"
+			height="{LayoutButton.BUTTON_SIZE}"
+			change="onSelectedItemChanged(event)"
+			disabledColor="{getStyle('color')}">
+	
+	<mate:Listener type="{LayoutEvent.APPLY_DEFAULT_LAYOUT_EVENT}" method="onApplyDefaultLayout" />
+	<mate:Listener type="{LayoutEvent.REMOTE_LOCK_LAYOUT_EVENT}" receive="{enabled=false || UserManager.getInstance().getConference().amIModerator()}" />
+	<mate:Listener type="{LayoutEvent.REMOTE_UNLOCK_LAYOUT_EVENT}" receive="{enabled=true}" />
+	<mate:Listener type="{LayoutEvent.INVALIDATE_LAYOUT_EVENT}" method="invalidadeLayout" />
+	<mate:Listener type="{LayoutsLoadedEvent.LAYOUTS_LOADED_EVENT}" method="populateLayoutsList" />
+	<mate:Listener type="{RedefineLayoutEvent.REDEFINE_LAYOUT_EVENT}" method="onRedefineLayout" />
+	
+	<mx:Script>
+		<![CDATA[
+			import com.asfusion.mate.events.Dispatcher;
+			import flash.events.Event;
+			import flash.events.ProgressEvent;
+			import flash.events.IOErrorEvent;
+			
+			import mx.controls.Alert;
+			import mx.events.ResizeEvent;
+			
+			import flash.net.FileReference;
+
+			import flexlib.mdi.managers.MDIManager;
+			import flexlib.mdi.containers.MDICanvas;
+			import flexlib.mdi.containers.MDIWindow;
+			import flexlib.mdi.events.MDIManagerEvent;
+			import flexlib.mdi.events.MDIWindowEvent;
+			
+			import org.bigbluebutton.common.IBbbModuleWindow;
+			import org.bigbluebutton.common.Images;
+			import org.bigbluebutton.common.LogUtil;
+			import org.bigbluebutton.common.events.OpenWindowEvent;
+			import org.bigbluebutton.core.managers.UserManager;
+			import org.bigbluebutton.main.views.MainToolbar;
+			import org.bigbluebutton.util.i18n.ResourceUtil;
+			import org.bigbluebutton.modules.layout.events.LayoutEvent;
+			import org.bigbluebutton.modules.layout.events.LayoutsLoadedEvent;
+			import org.bigbluebutton.modules.layout.events.RedefineLayoutEvent;
+			import org.bigbluebutton.modules.layout.events.ViewInitializedEvent;
+			import org.bigbluebutton.modules.layout.model.LayoutDefinitionFile;
+			import org.bigbluebutton.modules.layout.model.LayoutDefinition;
+			import org.bigbluebutton.modules.layout.model.WindowLayout;
+			import org.bigbluebutton.modules.layout.views.LayoutButton;
+			
+			private var _dispatcher:Dispatcher = new Dispatcher();
+			
+			private var _defaultLayout:Object = null;
+			
+			private function init():void {
+				LogUtil.debug("LayoutsCombo: view initialized");
+			}
+			
+			private function populateLayoutsList(e:LayoutsLoadedEvent):void {
+				LogUtil.debug("LayoutsCombo: populating list");
+				_defaultLayout = null;
+				dataProvider.removeAll();
+				var idx:int = 0;
+				for each (var value:LayoutDefinition in e.layouts.list) {
+					var item:Object = {index:idx, label:value.name, layout:value};
+					if (value.defaultLayout)
+						_defaultLayout = item;
+					dataProvider.addItem(item);
+					idx++;
+				}
+				invalidateDisplayList();
+			}
+			
+			private function onApplyDefaultLayout(e:Event):void {
+				if (_defaultLayout != null)
+					selectedItem = _defaultLayout; 
+			}
+			
+			private function onRedefineLayout(e:RedefineLayoutEvent):void {
+				/*
+				 *	remote means that the this event wasn't dispatched by this class
+				 *	it will come tipically from LayoutService or LayoutManager
+				 */
+				if (e.remote) {
+					var idx:int = -1;
+					prompt = e.layout.name;
+					
+					for each (var obj:Object in dataProvider) {
+						if (obj.label == e.layout.name)
+							idx = obj.index;
+					}
+					selectedIndex = idx;
+				}
+			}
+			
+			private function onSelectedItemChanged(e:Event):void {
+				LogUtil.debug("LayoutsCombo: different layout selected");
+				var redefineLayout:RedefineLayoutEvent = new RedefineLayoutEvent();
+				redefineLayout.layout = e.currentTarget.selectedItem.layout;
+				redefineLayout.remote = false;
+				_dispatcher.dispatchEvent(redefineLayout);
+			}
+			
+			private function invalidadeLayout(e:Event):void {
+				selectedIndex = -1;
+				prompt = ResourceUtil.getInstance().getString('bbb.layout.combo.custom');
+			}
+			
+		]]>
+	</mx:Script>
+</mx:ComboBox>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LoadButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LoadButton.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..4a83654875774880fb2190257bfa17a774ca0817
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LoadButton.mxml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+  Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+  This program 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; either version 2.1 of the License, or (at your option) any later
+  version.
+
+  BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+  Author: Felipe Cecagno <felipe@mconf.org>
+
+  $Id: $
+-->
+<views:LayoutButton xmlns:mx="http://www.adobe.com/2006/mxml" 
+		   creationComplete="init()" 
+		   xmlns:mate="http://mate.asfusion.com/"
+		   xmlns:views="org.bigbluebutton.modules.layout.views.*"
+		   toolTip="{ResourceUtil.getInstance().getString('bbb.layout.loadButton.toolTip')}"
+		   icon="{icon_load}"
+		   click="onClick(event)"
+		   enabled="{UserManager.getInstance().getConference().amIModerator()}">
+	
+	<mx:Script>
+		<![CDATA[
+			import com.asfusion.mate.events.Dispatcher;
+
+			import flash.events.Event;
+			
+			import org.bigbluebutton.common.Images;
+			import org.bigbluebutton.common.LogUtil;
+			import org.bigbluebutton.core.managers.UserManager;
+			import org.bigbluebutton.util.i18n.ResourceUtil;
+			import org.bigbluebutton.modules.layout.events.LayoutEvent;
+
+			private var _dispatcher:Dispatcher = new Dispatcher();
+			private var _images:Images = new Images();
+			[Bindable] private var icon_load:Class = _images.folder;
+			
+			private function init():void {
+			}
+			
+			private function onClick(e:Event):void {
+				_dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.LOAD_LAYOUTS_EVENT));
+			}
+			
+		]]>
+	</mx:Script>
+</views:LayoutButton>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LockButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LockButton.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..f04cf00a0f96f90b8d912e841aa2687e9c0df788
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LockButton.mxml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+  Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+  This program 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; either version 2.1 of the License, or (at your option) any later
+  version.
+
+  BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+  Author: Felipe Cecagno <felipe@mconf.org>
+
+  $Id: $
+-->
+<views:LayoutButton xmlns:mx="http://www.adobe.com/2006/mxml" 
+		   creationComplete="init()" 
+		   xmlns:mate="http://mate.asfusion.com/"
+		   xmlns:views="org.bigbluebutton.modules.layout.views.*"
+		   toolTip="{ResourceUtil.getInstance().getString('bbb.layout.lockButton.toolTip')}"
+		   icon="{icon_unlocked}"
+		   click="onClick(event)"
+		   enabled="{UserManager.getInstance().getConference().amIModerator()}">
+	
+	<mate:Listener type="{LayoutEvent.REMOTE_LOCK_LAYOUT_EVENT}" method="onLockLayoutEvent" />
+	<mate:Listener type="{LayoutEvent.REMOTE_UNLOCK_LAYOUT_EVENT}" method="onUnlockLayoutEvent" />
+
+	<mx:Script>
+		<![CDATA[
+			import com.asfusion.mate.events.Dispatcher;
+
+			import flash.events.Event;
+			
+			import org.bigbluebutton.common.Images;
+			import org.bigbluebutton.common.LogUtil;
+			import org.bigbluebutton.core.managers.UserManager;
+			import org.bigbluebutton.util.i18n.ResourceUtil;
+			import org.bigbluebutton.modules.layout.events.LayoutEvent;
+
+			private var _dispatcher:Dispatcher = new Dispatcher();
+			private var _images:Images = new Images();
+			[Bindable] private var icon_locked:Class = _images.locked;
+			[Bindable] private var icon_unlocked:Class = _images.unlocked;
+			
+			private function init():void {
+			}
+			
+			private function onClick(e:Event):void {
+				if (!this.selected) {
+					_dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.LOCK_LAYOUT_EVENT));
+				} else {
+					_dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.UNLOCK_LAYOUT_EVENT));
+				}
+			}
+			
+			private function onLockLayoutEvent(e:Event):void {
+				this.selected = true;
+				this.setStyle("icon", icon_locked);
+			}
+			
+			private function onUnlockLayoutEvent(e:Event):void {
+				this.selected = false;
+				this.setStyle("icon", icon_unlocked);
+			}
+			
+		]]>
+	</mx:Script>
+</views:LayoutButton>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/SaveButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/SaveButton.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..b22ad8230892a83f11b99cff4273ce191521b8d5
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/SaveButton.mxml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+  Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+  This program 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; either version 2.1 of the License, or (at your option) any later
+  version.
+
+  BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+  Author: Felipe Cecagno <felipe@mconf.org>
+
+  $Id: $
+-->
+<views:LayoutButton xmlns:mx="http://www.adobe.com/2006/mxml" 
+		   creationComplete="init()" 
+		   xmlns:mate="http://mate.asfusion.com/"
+		   xmlns:views="org.bigbluebutton.modules.layout.views.*"
+		   toolTip="{ResourceUtil.getInstance().getString('bbb.layout.saveButton.toolTip')}"
+		   icon="{icon_save}"
+		   click="onClick(event)"
+		   enabled="{UserManager.getInstance().getConference().amIModerator()}">
+	
+	<mx:Script>
+		<![CDATA[
+			import com.asfusion.mate.events.Dispatcher;
+
+			import flash.events.Event;
+			
+			import org.bigbluebutton.common.Images;
+			import org.bigbluebutton.common.LogUtil;
+			import org.bigbluebutton.core.managers.UserManager;
+			import org.bigbluebutton.util.i18n.ResourceUtil;
+			import org.bigbluebutton.modules.layout.events.LayoutEvent;
+
+			private var _dispatcher:Dispatcher = new Dispatcher();
+			private var _images:Images = new Images();
+			[Bindable] private var icon_save:Class = _images.disk;
+			
+			private function init():void {
+			}
+			
+			private function onClick(e:Event):void {
+				_dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.SAVE_LAYOUTS_EVENT));
+			}
+			
+		]]>
+	</mx:Script>
+</views:LayoutButton>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/ToolbarComponent.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/ToolbarComponent.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..4c83dd783517b9f1088a8a6f71a77982ea5be624
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/ToolbarComponent.mxml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+  Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+  This program 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; either version 2.1 of the License, or (at your option) any later
+  version.
+
+  BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+  Author: Felipe Cecagno <felipe@mconf.org>
+
+  $Id: $
+-->
+<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" 
+		   creationComplete="init()" 
+		   xmlns:mate="http://mate.asfusion.com/"
+		   xmlns:views="org.bigbluebutton.modules.layout.views.*"
+		   implements="org.bigbluebutton.common.IBbbToolbarComponent">
+	
+	<mx:Script>
+		<![CDATA[
+			import com.asfusion.mate.events.Dispatcher;
+
+			import flexlib.mdi.containers.MDICanvas;
+
+			import org.bigbluebutton.core.managers.UserManager;
+			import org.bigbluebutton.main.views.MainToolbar;
+			import org.bigbluebutton.modules.layout.events.ViewInitializedEvent;
+			import org.bigbluebutton.modules.layout.model.WindowLayout;
+
+			private var _dispatcher:Dispatcher = new Dispatcher();
+			[Bindable] private var _enableEdit:Boolean = false;
+			
+			private function init():void {
+				var evt:ViewInitializedEvent = new ViewInitializedEvent();
+				evt.canvas = getMdiCanvas(parent) as MDICanvas;
+				_dispatcher.dispatchEvent(evt);
+			}
+			
+			public function set enableEdit(arg:Boolean):void {
+				_enableEdit = arg && UserManager.getInstance().getConference().amIModerator();
+			}
+			
+			private function getMdiCanvas(p:DisplayObjectContainer):DisplayObject {
+				if (p == null)
+					return null;
+					
+				for (var i:int = 0; i < p.numChildren; ++i) {
+					//if (String(getQualifiedClassName(p.getChildAt(i))).match("MainCanvas"))
+					if (WindowLayout.getType(p.getChildAt(i)) == "MainCanvas") 
+						return p.getChildAt(i);
+					
+					var obj:DisplayObject = getMdiCanvas(p.parent);
+					if (obj != null)
+						return obj;
+				}
+				return null;
+			}
+			
+			public function getAlignment():String{
+				return MainToolbar.ALIGN_RIGHT;
+			}
+			
+		]]>
+	</mx:Script>
+
+	<views:LayoutsCombo id="comboBox" />
+	<views:AddButton id="addButton" 
+		includeInLayout="{_enableEdit}" visible="{_enableEdit}" />
+	<views:SaveButton id="saveButton" 
+		includeInLayout="{_enableEdit}" visible="{_enableEdit}" />
+	<views:LoadButton id="loadButton" 
+		includeInLayout="{_enableEdit}" visible="{_enableEdit}" />
+	<views:LockButton id="lockButton" />
+</mx:HBox>